Files
sdk/runtime/vm/dart_api_impl_test.cc
T
regis@google.com 1b8e614d7d Change compile-time errors into dynamic errors in instance creation expression
(issue 3085).
Change compile-time errors into dynamic errors in static getter and setter
calls (issues 3088, 3094).
Fix a crash in flow graph builder for missing static getter (issue 4360).
Add support in VM for NoSuchMethodError.
Remove support in VM for StaticResolutionException.
Add, remove, update related language tests.
Triage related co19 tests.
Review URL: https://codereview.chromium.org//11049038

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@13208 260f80e4-7a28-3924-810f-c04153c831b5
2012-10-04 00:15:38 +00:00

7153 lines
230 KiB
C++

// Copyright (c) 2012, 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 "include/dart_api.h"
#include "platform/assert.h"
#include "platform/json.h"
#include "platform/utils.h"
#include "vm/class_finalizer.h"
#include "vm/dart_api_impl.h"
#include "vm/dart_api_state.h"
#include "vm/thread.h"
#include "vm/unit_test.h"
#include "vm/verifier.h"
namespace dart {
DECLARE_FLAG(bool, enable_type_checks);
// Only ia32 and x64 can run execution tests.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
TEST_CASE(ErrorHandleBasics) {
const char* kScriptChars =
"void testMain() {\n"
" throw new Exception(\"bad news\");\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle instance = Dart_True();
Dart_Handle error = Api::NewError("myerror");
Dart_Handle exception = Dart_Invoke(lib,
Dart_NewString("testMain"),
0,
NULL);
EXPECT_VALID(instance);
EXPECT(Dart_IsError(error));
EXPECT(Dart_IsError(exception));
EXPECT(!Dart_ErrorHasException(instance));
EXPECT(!Dart_ErrorHasException(error));
EXPECT(Dart_ErrorHasException(exception));
EXPECT_STREQ("", Dart_GetError(instance));
EXPECT_STREQ("myerror", Dart_GetError(error));
EXPECT_STREQ(
"Unhandled exception:\n"
"Exception: bad news\n"
"#0 testMain (dart:test-lib:2:3)",
Dart_GetError(exception));
EXPECT(Dart_IsError(Dart_ErrorGetException(instance)));
EXPECT(Dart_IsError(Dart_ErrorGetException(error)));
EXPECT_VALID(Dart_ErrorGetException(exception));
EXPECT(Dart_IsError(Dart_ErrorGetStacktrace(instance)));
EXPECT(Dart_IsError(Dart_ErrorGetStacktrace(error)));
EXPECT_VALID(Dart_ErrorGetStacktrace(exception));
}
TEST_CASE(ErrorHandleTypes) {
Isolate* isolate = Isolate::Current();
const String& compile_message = String::Handle(String::New("CompileError"));
const String& fatal_message = String::Handle(String::New("FatalError"));
Dart_Handle not_error = Dart_NewString("NotError");
Dart_Handle api_error = Dart_NewApiError("Api%s", "Error");
Dart_Handle exception_error =
Dart_NewUnhandledExceptionError(Dart_NewString("ExceptionError"));
Dart_Handle compile_error =
Api::NewHandle(isolate, LanguageError::New(compile_message));
Dart_Handle fatal_error =
Api::NewHandle(isolate, UnwindError::New(fatal_message));
EXPECT_VALID(not_error);
EXPECT(Dart_IsError(api_error));
EXPECT(Dart_IsError(exception_error));
EXPECT(Dart_IsError(compile_error));
EXPECT(Dart_IsError(fatal_error));
EXPECT(!Dart_IsApiError(not_error));
EXPECT(Dart_IsApiError(api_error));
EXPECT(!Dart_IsApiError(exception_error));
EXPECT(!Dart_IsApiError(compile_error));
EXPECT(!Dart_IsApiError(fatal_error));
EXPECT(!Dart_IsUnhandledExceptionError(not_error));
EXPECT(!Dart_IsUnhandledExceptionError(api_error));
EXPECT(Dart_IsUnhandledExceptionError(exception_error));
EXPECT(!Dart_IsUnhandledExceptionError(compile_error));
EXPECT(!Dart_IsUnhandledExceptionError(fatal_error));
EXPECT(!Dart_IsCompilationError(not_error));
EXPECT(!Dart_IsCompilationError(api_error));
EXPECT(!Dart_IsCompilationError(exception_error));
EXPECT(Dart_IsCompilationError(compile_error));
EXPECT(!Dart_IsCompilationError(fatal_error));
EXPECT(!Dart_IsFatalError(not_error));
EXPECT(!Dart_IsFatalError(api_error));
EXPECT(!Dart_IsFatalError(exception_error));
EXPECT(!Dart_IsFatalError(compile_error));
EXPECT(Dart_IsFatalError(fatal_error));
EXPECT_STREQ("", Dart_GetError(not_error));
EXPECT_STREQ("ApiError", Dart_GetError(api_error));
EXPECT_SUBSTRING("Unhandled exception:\nExceptionError",
Dart_GetError(exception_error));
EXPECT_STREQ("CompileError", Dart_GetError(compile_error));
EXPECT_STREQ("FatalError", Dart_GetError(fatal_error));
}
void PropagateErrorNative(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle closure = Dart_GetNativeArgument(args, 0);
EXPECT(Dart_IsClosure(closure));
Dart_Handle result = Dart_InvokeClosure(closure, 0, NULL);
EXPECT(Dart_IsError(result));
result = Dart_PropagateError(result);
EXPECT_VALID(result); // We do not expect to reach here.
UNREACHABLE();
}
static Dart_NativeFunction PropagateError_native_lookup(
Dart_Handle name, int argument_count) {
return reinterpret_cast<Dart_NativeFunction>(&PropagateErrorNative);
}
TEST_CASE(Dart_PropagateError) {
const char* kScriptChars =
"raiseCompileError() {\n"
" return missing_semicolon\n"
"}\n"
"\n"
"void throwException() {\n"
" throw new Exception('myException');\n"
"}\n"
"\n"
"void nativeFunc(closure) native 'Test_nativeFunc';\n"
"\n"
"void Func1() {\n"
" nativeFunc(() => raiseCompileError());\n"
"}\n"
"\n"
"void Func2() {\n"
" nativeFunc(() => throwException());\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(
kScriptChars, &PropagateError_native_lookup);
Dart_Handle result;
result = Dart_Invoke(lib, Dart_NewString("Func1"), 0, NULL);
EXPECT(Dart_IsError(result));
EXPECT(!Dart_ErrorHasException(result));
EXPECT_SUBSTRING("semicolon expected", Dart_GetError(result));
result = Dart_Invoke(lib, Dart_NewString("Func2"), 0, NULL);
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result));
EXPECT_SUBSTRING("myException", Dart_GetError(result));
}
#endif
TEST_CASE(Dart_Error) {
Dart_Handle error = Dart_Error("An %s", "error");
EXPECT(Dart_IsError(error));
EXPECT_STREQ("An error", Dart_GetError(error));
}
TEST_CASE(Null) {
Dart_Handle null = Dart_Null();
EXPECT_VALID(null);
EXPECT(Dart_IsNull(null));
Dart_Handle str = Dart_NewString("test");
EXPECT_VALID(str);
EXPECT(!Dart_IsNull(str));
}
TEST_CASE(IdentityEquals) {
Dart_Handle five = Dart_NewString("5");
Dart_Handle five_again = Dart_NewString("5");
Dart_Handle seven = Dart_NewString("7");
// Same objects.
EXPECT(Dart_IdentityEquals(five, five));
// Equal objects.
EXPECT(!Dart_IdentityEquals(five, five_again));
// Different objects.
EXPECT(!Dart_IdentityEquals(five, seven));
// Non-instance objects.
{
Isolate* isolate = Isolate::Current();
DARTSCOPE_NOCHECKS(isolate);
Dart_Handle class1 = Api::NewHandle(isolate, Object::null_class());
Dart_Handle class2 = Api::NewHandle(isolate, Object::class_class());
EXPECT(Dart_IdentityEquals(class1, class1));
EXPECT(!Dart_IdentityEquals(class1, class2));
}
}
// Only ia32 and x64 can run execution tests.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
TEST_CASE(ObjectEquals) {
bool equal = false;
Dart_Handle five = Dart_NewString("5");
Dart_Handle five_again = Dart_NewString("5");
Dart_Handle seven = Dart_NewString("7");
// Same objects.
EXPECT_VALID(Dart_ObjectEquals(five, five, &equal));
EXPECT(equal);
// Equal objects.
EXPECT_VALID(Dart_ObjectEquals(five, five_again, &equal));
EXPECT(equal);
// Different objects.
EXPECT_VALID(Dart_ObjectEquals(five, seven, &equal));
EXPECT(!equal);
}
#endif
TEST_CASE(InstanceValues) {
EXPECT(Dart_IsInstance(Dart_NewString("test")));
EXPECT(Dart_IsInstance(Dart_True()));
// By convention, our Is*() functions exclude null.
EXPECT(!Dart_IsInstance(Dart_Null()));
}
TEST_CASE(InstanceGetClass) {
// Get the handle from a valid instance handle.
Dart_Handle instance = Dart_True();
Dart_Handle cls = Dart_InstanceGetClass(instance);
EXPECT_VALID(cls);
EXPECT(Dart_IsClass(cls));
Dart_Handle cls_name = Dart_ClassName(cls);
EXPECT_VALID(cls_name);
const char* cls_name_cstr = "";
EXPECT_VALID(Dart_StringToCString(cls_name, &cls_name_cstr));
EXPECT_STREQ("bool", cls_name_cstr);
// Errors propagate.
Dart_Handle error = Dart_NewApiError("MyError");
Dart_Handle error_cls = Dart_InstanceGetClass(error);
EXPECT_ERROR(error_cls, "MyError");
// Get the handle from a non-instance handle
ASSERT(Dart_IsClass(cls));
Dart_Handle cls_cls = Dart_InstanceGetClass(cls);
EXPECT_ERROR(cls_cls,
"Dart_InstanceGetClass expects argument 'instance' to be of "
"type Instance.");
}
TEST_CASE(BooleanValues) {
Dart_Handle str = Dart_NewString("test");
EXPECT(!Dart_IsBoolean(str));
bool value = false;
Dart_Handle result = Dart_BooleanValue(str, &value);
EXPECT(Dart_IsError(result));
Dart_Handle val1 = Dart_NewBoolean(true);
EXPECT(Dart_IsBoolean(val1));
result = Dart_BooleanValue(val1, &value);
EXPECT_VALID(result);
EXPECT(value);
Dart_Handle val2 = Dart_NewBoolean(false);
EXPECT(Dart_IsBoolean(val2));
result = Dart_BooleanValue(val2, &value);
EXPECT_VALID(result);
EXPECT(!value);
}
TEST_CASE(BooleanConstants) {
Dart_Handle true_handle = Dart_True();
EXPECT_VALID(true_handle);
EXPECT(Dart_IsBoolean(true_handle));
bool value = false;
Dart_Handle result = Dart_BooleanValue(true_handle, &value);
EXPECT_VALID(result);
EXPECT(value);
Dart_Handle false_handle = Dart_False();
EXPECT_VALID(false_handle);
EXPECT(Dart_IsBoolean(false_handle));
result = Dart_BooleanValue(false_handle, &value);
EXPECT_VALID(result);
EXPECT(!value);
}
TEST_CASE(DoubleValues) {
const double kDoubleVal1 = 201.29;
const double kDoubleVal2 = 101.19;
Dart_Handle val1 = Dart_NewDouble(kDoubleVal1);
EXPECT(Dart_IsDouble(val1));
Dart_Handle val2 = Dart_NewDouble(kDoubleVal2);
EXPECT(Dart_IsDouble(val2));
double out1, out2;
Dart_Handle result = Dart_DoubleValue(val1, &out1);
EXPECT_VALID(result);
EXPECT_EQ(kDoubleVal1, out1);
result = Dart_DoubleValue(val2, &out2);
EXPECT_VALID(result);
EXPECT_EQ(kDoubleVal2, out2);
}
// Only ia32 and x64 can run execution tests.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
TEST_CASE(NumberValues) {
// TODO(antonm): add various kinds of ints (smi, mint, bigint).
const char* kScriptChars =
"int getInt() { return 1; }\n"
"double getDouble() { return 1.0; }\n"
"bool getBool() { return false; }\n"
"getNull() { return null; }\n";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Check int case.
result = Dart_Invoke(lib, Dart_NewString("getInt"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsNumber(result));
// Check double case.
result = Dart_Invoke(lib, Dart_NewString("getDouble"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsNumber(result));
// Check bool case.
result = Dart_Invoke(lib, Dart_NewString("getBool"), 0, NULL);
EXPECT_VALID(result);
EXPECT(!Dart_IsNumber(result));
// Check null case.
result = Dart_Invoke(lib, Dart_NewString("getNull"), 0, NULL);
EXPECT_VALID(result);
EXPECT(!Dart_IsNumber(result));
}
#endif
TEST_CASE(IntegerValues) {
const int64_t kIntegerVal1 = 100;
const int64_t kIntegerVal2 = 0xffffffff;
const char* kIntegerVal3 = "0x123456789123456789123456789";
Dart_Handle val1 = Dart_NewInteger(kIntegerVal1);
EXPECT(Dart_IsInteger(val1));
bool fits = false;
Dart_Handle result = Dart_IntegerFitsIntoInt64(val1, &fits);
EXPECT_VALID(result);
EXPECT(fits);
Dart_Handle val2 = Dart_NewInteger(kIntegerVal2);
EXPECT(Dart_IsInteger(val2));
result = Dart_IntegerFitsIntoInt64(val2, &fits);
EXPECT_VALID(result);
EXPECT(fits);
Dart_Handle val3 = Dart_NewIntegerFromHexCString(kIntegerVal3);
EXPECT(Dart_IsInteger(val3));
result = Dart_IntegerFitsIntoInt64(val3, &fits);
EXPECT_VALID(result);
EXPECT(!fits);
int64_t out = 0;
result = Dart_IntegerToInt64(val1, &out);
EXPECT_VALID(result);
EXPECT_EQ(kIntegerVal1, out);
result = Dart_IntegerToInt64(val2, &out);
EXPECT_VALID(result);
EXPECT_EQ(kIntegerVal2, out);
const char* chars = NULL;
result = Dart_IntegerToHexCString(val3, &chars);
EXPECT_VALID(result);
EXPECT(!strcmp(kIntegerVal3, chars));
}
TEST_CASE(IntegerFitsIntoInt64) {
Dart_Handle max = Dart_NewInteger(kMaxInt64);
EXPECT(Dart_IsInteger(max));
bool fits = false;
Dart_Handle result = Dart_IntegerFitsIntoInt64(max, &fits);
EXPECT_VALID(result);
EXPECT(fits);
Dart_Handle above_max = Dart_NewIntegerFromHexCString("0x8000000000000000");
EXPECT(Dart_IsInteger(above_max));
fits = true;
result = Dart_IntegerFitsIntoInt64(above_max, &fits);
EXPECT_VALID(result);
EXPECT(!fits);
Dart_Handle min = Dart_NewInteger(kMaxInt64);
EXPECT(Dart_IsInteger(min));
fits = false;
result = Dart_IntegerFitsIntoInt64(min, &fits);
EXPECT_VALID(result);
EXPECT(fits);
Dart_Handle below_min = Dart_NewIntegerFromHexCString("-0x8000000000000001");
EXPECT(Dart_IsInteger(below_min));
fits = true;
result = Dart_IntegerFitsIntoInt64(below_min, &fits);
EXPECT_VALID(result);
EXPECT(!fits);
}
TEST_CASE(IntegerFitsIntoUint64) {
Dart_Handle max = Dart_NewIntegerFromHexCString("0xFFFFFFFFFFFFFFFF");
EXPECT(Dart_IsInteger(max));
bool fits = false;
Dart_Handle result = Dart_IntegerFitsIntoUint64(max, &fits);
EXPECT_VALID(result);
EXPECT(fits);
Dart_Handle above_max = Dart_NewIntegerFromHexCString("0x10000000000000000");
EXPECT(Dart_IsInteger(above_max));
fits = true;
result = Dart_IntegerFitsIntoUint64(above_max, &fits);
EXPECT_VALID(result);
EXPECT(!fits);
Dart_Handle min = Dart_NewInteger(0);
EXPECT(Dart_IsInteger(min));
fits = false;
result = Dart_IntegerFitsIntoUint64(min, &fits);
EXPECT_VALID(result);
EXPECT(fits);
Dart_Handle below_min = Dart_NewIntegerFromHexCString("-1");
EXPECT(Dart_IsInteger(below_min));
fits = true;
result = Dart_IntegerFitsIntoUint64(below_min, &fits);
EXPECT_VALID(result);
EXPECT(!fits);
}
TEST_CASE(ArrayValues) {
const int kArrayLength = 10;
Dart_Handle str = Dart_NewString("test");
EXPECT(!Dart_IsList(str));
Dart_Handle val = Dart_NewList(kArrayLength);
EXPECT(Dart_IsList(val));
intptr_t len = 0;
Dart_Handle result = Dart_ListLength(val, &len);
EXPECT_VALID(result);
EXPECT_EQ(kArrayLength, len);
// Check invalid array access.
result = Dart_ListSetAt(val, (kArrayLength + 10), Dart_NewInteger(10));
EXPECT(Dart_IsError(result));
result = Dart_ListSetAt(val, -10, Dart_NewInteger(10));
EXPECT(Dart_IsError(result));
result = Dart_ListGetAt(val, (kArrayLength + 10));
EXPECT(Dart_IsError(result));
result = Dart_ListGetAt(val, -10);
EXPECT(Dart_IsError(result));
for (int i = 0; i < kArrayLength; i++) {
result = Dart_ListSetAt(val, i, Dart_NewInteger(i));
EXPECT_VALID(result);
}
for (int i = 0; i < kArrayLength; i++) {
result = Dart_ListGetAt(val, i);
EXPECT_VALID(result);
int64_t value;
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(i, value);
}
}
TEST_CASE(IsString) {
uint8_t data8[] = { 'o', 'n', 'e', 0xFF };
Dart_Handle str8 = Dart_NewString8(data8, ARRAY_SIZE(data8));
EXPECT_VALID(str8);
EXPECT(Dart_IsString(str8));
EXPECT(Dart_IsString8(str8));
EXPECT(Dart_IsString16(str8));
EXPECT(!Dart_IsExternalString(str8));
Dart_Handle ext8 = Dart_NewExternalString8(data8, ARRAY_SIZE(data8),
NULL, NULL);
EXPECT_VALID(ext8);
EXPECT(Dart_IsString(ext8));
EXPECT(Dart_IsString8(ext8));
EXPECT(Dart_IsString16(ext8));
EXPECT(Dart_IsExternalString(ext8));
uint16_t data16[] = { 't', 'w', 'o', 0xFFFF };
Dart_Handle str16 = Dart_NewString16(data16, ARRAY_SIZE(data16));
EXPECT_VALID(str16);
EXPECT(Dart_IsString(str16));
EXPECT(!Dart_IsString8(str16));
EXPECT(Dart_IsString16(str16));
EXPECT(!Dart_IsExternalString(str16));
Dart_Handle ext16 = Dart_NewExternalString16(data16, ARRAY_SIZE(data16),
NULL, NULL);
EXPECT_VALID(ext16);
EXPECT(Dart_IsString(ext16));
EXPECT(!Dart_IsString8(ext16));
EXPECT(Dart_IsString16(ext16));
EXPECT(Dart_IsExternalString(ext16));
uint32_t data32[] = { 'f', 'o', 'u', 'r', 0x10FFFF };
Dart_Handle str32 = Dart_NewString32(data32, ARRAY_SIZE(data32));
EXPECT_VALID(str32);
EXPECT(Dart_IsString(str32));
EXPECT(!Dart_IsString8(str32));
EXPECT(!Dart_IsString16(str32));
EXPECT(!Dart_IsExternalString(str32));
Dart_Handle ext32 = Dart_NewExternalString32(data32, ARRAY_SIZE(data32),
NULL, NULL);
EXPECT_VALID(ext32);
EXPECT(Dart_IsString(ext32));
EXPECT(!Dart_IsString8(ext32));
EXPECT(!Dart_IsString16(ext32));
EXPECT(Dart_IsExternalString(ext32));
}
TEST_CASE(NewString) {
const char* ascii = "string";
Dart_Handle ascii_str = Dart_NewString(ascii);
EXPECT_VALID(ascii_str);
EXPECT(Dart_IsString(ascii_str));
const char* null = NULL;
Dart_Handle null_str = Dart_NewString(null);
EXPECT(Dart_IsError(null_str));
const char* utf8 = "\xE4\xBA\x8C"; // U+4E8C
Dart_Handle utf8_str = Dart_NewString(utf8);
EXPECT_VALID(utf8_str);
EXPECT(Dart_IsString(utf8_str));
const char* invalid = "\xE4\xBA"; // underflow
Dart_Handle invalid_str = Dart_NewString(invalid);
EXPECT(Dart_IsError(invalid_str));
}
TEST_CASE(ExternalStringGetPeer) {
Dart_Handle result;
uint8_t data8[] = { 'o', 'n', 'e', 0xFF };
int peer_data = 123;
void* peer = NULL;
// Success.
Dart_Handle ext8 = Dart_NewExternalString8(data8, ARRAY_SIZE(data8),
&peer_data, NULL);
EXPECT_VALID(ext8);
result = Dart_ExternalStringGetPeer(ext8, &peer);
EXPECT_VALID(result);
EXPECT_EQ(&peer_data, peer);
// NULL peer.
result = Dart_ExternalStringGetPeer(ext8, NULL);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_ExternalStringGetPeer expects argument 'peer' to be "
"non-null.", Dart_GetError(result));
// String is not external.
peer = NULL;
Dart_Handle str8 = Dart_NewString8(data8, ARRAY_SIZE(data8));
EXPECT_VALID(str8);
result = Dart_ExternalStringGetPeer(str8, &peer);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_ExternalStringGetPeer expects argument 'object' to be "
"an external String.", Dart_GetError(result));
EXPECT(peer == NULL);
// Not a String.
peer = NULL;
result = Dart_ExternalStringGetPeer(Dart_True(), &peer);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_ExternalStringGetPeer expects argument 'object' to be "
"of type String.", Dart_GetError(result));
EXPECT(peer == NULL);
}
// Only ia32 and x64 can run execution tests.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
static void ExternalStringCallbackFinalizer(void* peer) {
*static_cast<int*>(peer) *= 2;
}
TEST_CASE(ExternalStringCallback) {
int peer8 = 40;
int peer16 = 41;
int peer32 = 42;
{
Dart_EnterScope();
uint8_t data8[] = { 'h', 'e', 'l', 'l', 'o' };
Dart_Handle obj8 = Dart_NewExternalString8(
data8,
ARRAY_SIZE(data8),
&peer8,
ExternalStringCallbackFinalizer);
EXPECT_VALID(obj8);
void* api_peer8 = NULL;
EXPECT_VALID(Dart_ExternalStringGetPeer(obj8, &api_peer8));
EXPECT_EQ(api_peer8, &peer8);
uint16_t data16[] = { 'h', 'e', 'l', 'l', 'o' };
Dart_Handle obj16 = Dart_NewExternalString16(
data16,
ARRAY_SIZE(data16),
&peer16,
ExternalStringCallbackFinalizer);
EXPECT_VALID(obj16);
void* api_peer16 = NULL;
EXPECT_VALID(Dart_ExternalStringGetPeer(obj16, &api_peer16));
EXPECT_EQ(api_peer16, &peer16);
uint32_t data32[] = { 'h', 'e', 'l', 'l', 'o' };
Dart_Handle obj32 = Dart_NewExternalString32(
data32,
ARRAY_SIZE(data32),
&peer32,
ExternalStringCallbackFinalizer);
EXPECT_VALID(obj32);
void* api_peer32 = NULL;
EXPECT_VALID(Dart_ExternalStringGetPeer(obj32, &api_peer32));
EXPECT_EQ(api_peer32, &peer32);
Dart_ExitScope();
}
EXPECT_EQ(40, peer8);
EXPECT_EQ(41, peer16);
EXPECT_EQ(42, peer32);
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(40, peer8);
EXPECT_EQ(41, peer16);
EXPECT_EQ(42, peer32);
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
EXPECT_EQ(80, peer8);
EXPECT_EQ(82, peer16);
EXPECT_EQ(84, peer32);
}
TEST_CASE(ListAccess) {
const char* kScriptChars =
"List testMain() {"
" List a = new List();"
" a.add(10);"
" a.add(20);"
" a.add(30);"
" return a;"
"}";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns an object of type List.
result = Dart_Invoke(lib, Dart_NewString("testMain"), 0, NULL);
EXPECT_VALID(result);
// First ensure that the returned object is an array.
Dart_Handle ListAccessTestObj = result;
EXPECT(Dart_IsList(ListAccessTestObj));
// Get length of array object.
intptr_t len = 0;
result = Dart_ListLength(ListAccessTestObj, &len);
EXPECT_VALID(result);
EXPECT_EQ(3, len);
// Access elements in the array.
int64_t value;
result = Dart_ListGetAt(ListAccessTestObj, 0);
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(10, value);
result = Dart_ListGetAt(ListAccessTestObj, 1);
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(20, value);
result = Dart_ListGetAt(ListAccessTestObj, 2);
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(30, value);
// Set some elements in the array.
result = Dart_ListSetAt(ListAccessTestObj, 0, Dart_NewInteger(0));
EXPECT_VALID(result);
result = Dart_ListSetAt(ListAccessTestObj, 1, Dart_NewInteger(1));
EXPECT_VALID(result);
result = Dart_ListSetAt(ListAccessTestObj, 2, Dart_NewInteger(2));
EXPECT_VALID(result);
// Get length of array object.
result = Dart_ListLength(ListAccessTestObj, &len);
EXPECT_VALID(result);
EXPECT_EQ(3, len);
// Now try and access these elements in the array.
result = Dart_ListGetAt(ListAccessTestObj, 0);
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(0, value);
result = Dart_ListGetAt(ListAccessTestObj, 1);
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(1, value);
result = Dart_ListGetAt(ListAccessTestObj, 2);
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(2, value);
uint8_t native_array[3];
result = Dart_ListGetAsBytes(ListAccessTestObj, 0, native_array, 3);
EXPECT_VALID(result);
EXPECT_EQ(0, native_array[0]);
EXPECT_EQ(1, native_array[1]);
EXPECT_EQ(2, native_array[2]);
native_array[0] = 10;
native_array[1] = 20;
native_array[2] = 30;
result = Dart_ListSetAsBytes(ListAccessTestObj, 0, native_array, 3);
EXPECT_VALID(result);
result = Dart_ListGetAsBytes(ListAccessTestObj, 0, native_array, 3);
EXPECT_VALID(result);
EXPECT_EQ(10, native_array[0]);
EXPECT_EQ(20, native_array[1]);
EXPECT_EQ(30, native_array[2]);
result = Dart_ListGetAt(ListAccessTestObj, 2);
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(30, value);
// Check if we get an exception when accessing beyond limit.
result = Dart_ListGetAt(ListAccessTestObj, 4);
EXPECT(Dart_IsError(result));
}
TEST_CASE(ByteArrayAccess) {
Dart_Handle byte_array1 = Dart_NewByteArray(10);
EXPECT_VALID(byte_array1);
EXPECT(Dart_IsByteArray(byte_array1));
EXPECT(Dart_IsList(byte_array1));
intptr_t length = 0;
Dart_Handle result = Dart_ListLength(byte_array1, &length);
EXPECT_VALID(result);
EXPECT_EQ(10, length);
result = Dart_ListSetAt(byte_array1, -1, Dart_NewInteger(1));
EXPECT(Dart_IsError(result));
result = Dart_ByteArraySetUint8At(byte_array1, -1, 1);
EXPECT(Dart_IsError(result));
result = Dart_ListSetAt(byte_array1, 10, Dart_NewInteger(1));
EXPECT(Dart_IsError(result));
result = Dart_ByteArraySetUint8At(byte_array1, 10, 1);
EXPECT(Dart_IsError(result));
// Set through the List API.
for (intptr_t i = 0; i < 10; ++i) {
EXPECT_VALID(Dart_ListSetAt(byte_array1, i, Dart_NewInteger(i + 1)));
}
for (intptr_t i = 0; i < 10; ++i) {
// Get through the List API.
Dart_Handle integer_obj = Dart_ListGetAt(byte_array1, i);
EXPECT_VALID(integer_obj);
int64_t int64_t_value = -1;
EXPECT_VALID(Dart_IntegerToInt64(integer_obj, &int64_t_value));
EXPECT_EQ(i + 1, int64_t_value);
// Get through the ByteArray API.
uint8_t uint8_t_value = 0xFF;
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array1, i, &uint8_t_value));
EXPECT_EQ(i + 1, uint8_t_value);
}
// Set through the ByteArray API.
for (intptr_t i = 0; i < 10; ++i) {
EXPECT_VALID(Dart_ByteArraySetUint8At(byte_array1, i, i + 2));
}
for (intptr_t i = 0; i < 10; ++i) {
// Get through the List API.
Dart_Handle integer_obj = Dart_ListGetAt(byte_array1, i);
EXPECT_VALID(integer_obj);
int64_t int64_t_value = -1;
EXPECT_VALID(Dart_IntegerToInt64(integer_obj, &int64_t_value));
EXPECT_EQ(i + 2, int64_t_value);
// Get through the ByteArray API.
uint8_t uint8_t_value = 0xFF;
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array1, i, &uint8_t_value));
EXPECT_EQ(i + 2, uint8_t_value);
}
Dart_Handle byte_array2 = Dart_NewByteArray(10);
bool is_equal = false;
Dart_ObjectEquals(byte_array1, byte_array2, &is_equal);
EXPECT(!is_equal);
// Set through the List API.
for (intptr_t i = 0; i < 10; ++i) {
result = Dart_ListSetAt(byte_array2, i, Dart_NewInteger(i + 2));
EXPECT_VALID(result);
}
for (intptr_t i = 0; i < 10; ++i) {
// Get through the List API.
Dart_Handle e1 = Dart_ListGetAt(byte_array1, i);
Dart_Handle e2 = Dart_ListGetAt(byte_array2, i);
is_equal = false;
Dart_ObjectEquals(e1, e2, &is_equal);
EXPECT(is_equal);
// Get through the ByteArray API.
uint8_t v1 = 0xFF;
uint8_t v2 = 0XFF;
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array1, i, &v1));
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array2, i, &v2));
EXPECT_NE(v1, 0xFF);
EXPECT_NE(v2, 0xFF);
EXPECT_EQ(v1, v2);
}
byte_array2 = Dart_NewByteArray(10);
is_equal = false;
Dart_ObjectEquals(byte_array1, byte_array2, &is_equal);
EXPECT(!is_equal);
// Set through the ByteArray API.
for (intptr_t i = 0; i < 10; ++i) {
result = Dart_ByteArraySetUint8At(byte_array2, i, i + 2);
EXPECT_VALID(result);
}
for (intptr_t i = 0; i < 10; ++i) {
// Get through the List API.
Dart_Handle e1 = Dart_ListGetAt(byte_array1, i);
Dart_Handle e2 = Dart_ListGetAt(byte_array2, i);
is_equal = false;
Dart_ObjectEquals(e1, e2, &is_equal);
EXPECT(is_equal);
// Get through the ByteArray API.
uint8_t v1 = 0xFF;
uint8_t v2 = 0XFF;
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array1, i, &v1));
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array2, i, &v2));
EXPECT_NE(v1, 0xFF);
EXPECT_NE(v2, 0xFF);
EXPECT_EQ(v1, v2);
}
uint8_t data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
result = Dart_ListSetAsBytes(byte_array1, 0, data, 10);
EXPECT_VALID(result);
for (intptr_t i = 0; i < 10; ++i) {
Dart_Handle integer_obj = Dart_ListGetAt(byte_array1, i);
EXPECT_VALID(integer_obj);
int64_t int64_t_value = -1;
EXPECT_VALID(Dart_IntegerToInt64(integer_obj, &int64_t_value));
EXPECT_EQ(i, int64_t_value);
uint8_t uint8_t_value = 0xFF;
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array1, i, &uint8_t_value));
EXPECT_EQ(i, uint8_t_value);
}
for (intptr_t i = 0; i < 10; ++i) {
EXPECT_VALID(Dart_ListSetAt(byte_array1, i, Dart_NewInteger(10 - i)));
}
Dart_ListGetAsBytes(byte_array1, 0, data, 10);
for (intptr_t i = 0; i < 10; ++i) {
Dart_Handle integer_obj = Dart_ListGetAt(byte_array1, i);
EXPECT_VALID(integer_obj);
int64_t int64_t_value = -1;
EXPECT_VALID(Dart_IntegerToInt64(integer_obj, &int64_t_value));
EXPECT_EQ(10 - i, int64_t_value);
uint8_t uint8_t_value = 0xFF;
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array1, i, &uint8_t_value));
EXPECT_EQ(10 - i, uint8_t_value);
}
for (intptr_t i = 0; i < 10; ++i) {
EXPECT_VALID(Dart_ByteArraySetUint8At(byte_array1, i, 10 + i));
}
Dart_ListGetAsBytes(byte_array1, 0, data, 10);
for (intptr_t i = 0; i < 10; ++i) {
Dart_Handle integer_obj = Dart_ListGetAt(byte_array1, i);
EXPECT_VALID(integer_obj);
int64_t int64_t_value = -1;
EXPECT_VALID(Dart_IntegerToInt64(integer_obj, &int64_t_value));
EXPECT_EQ(10 + i, int64_t_value);
uint8_t uint8_t_value = 0xFF;
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array1, i, &uint8_t_value));
EXPECT_EQ(10 + i, uint8_t_value);
}
}
TEST_CASE(ByteArrayAlignedMultiByteAccess) {
intptr_t length = 16;
Dart_Handle byte_array = Dart_NewByteArray(length);
intptr_t api_length = 0;
EXPECT_VALID(Dart_ListLength(byte_array, &api_length));
EXPECT_EQ(length, api_length);
// 4-byte aligned sets.
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 0, FLT_MIN));
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 4, FLT_MAX));
float float_value = 0.0f;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 0, &float_value));
EXPECT_EQ(FLT_MIN, float_value);
float_value = 0.0f;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 4, &float_value));
EXPECT_EQ(FLT_MAX, float_value);
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 0, 0.0f));
float_value = FLT_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 0, &float_value));
EXPECT_EQ(0.0f, float_value);
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 4, 1.0f));
float_value = FLT_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 4, &float_value));
EXPECT_EQ(1.0f, float_value);
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 0, -1.0f));
float_value = FLT_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 0, &float_value));
EXPECT_EQ(-1.0f, float_value);
// 8-byte aligned sets.
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 0, DBL_MIN));
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 8, DBL_MAX));
double double_value = 0.0;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 0, &double_value));
EXPECT_EQ(DBL_MIN, double_value);
double_value = 0.0;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 8, &double_value));
EXPECT_EQ(DBL_MAX, double_value);
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 0, 0.0));
double_value = DBL_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 0, &double_value));
EXPECT_EQ(0.0, double_value);
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 8, 1.0));
double_value = DBL_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 8, &double_value));
EXPECT_EQ(1.0, double_value);
}
TEST_CASE(ByteArrayMisalignedMultiByteAccess) {
intptr_t length = 17;
Dart_Handle byte_array = Dart_NewByteArray(length);
intptr_t api_length = 0;
EXPECT_VALID(Dart_ListLength(byte_array, &api_length));
EXPECT_EQ(length, api_length);
// 4-byte misaligned sets.
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 1, FLT_MIN));
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 5, FLT_MAX));
float float_value = 0.0f;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 1, &float_value));
EXPECT_EQ(FLT_MIN, float_value);
float_value = 0.0f;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 5, &float_value));
EXPECT_EQ(FLT_MAX, float_value);
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 1, 0.0f));
float_value = FLT_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 1, &float_value));
EXPECT_EQ(0.0f, float_value);
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 5, -0.0f));
float_value = FLT_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 5, &float_value));
EXPECT_EQ(-0.0f, float_value);
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 5, 1.0f));
float_value = FLT_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 5, &float_value));
EXPECT_EQ(1.0f, float_value);
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 1, -1.0f));
float_value = FLT_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 1, &float_value));
EXPECT_EQ(-1.0f, float_value);
// 8-byte misaligned sets.
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 1, DBL_MIN));
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 9, DBL_MAX));
double double_value = 0.0;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 1, &double_value));
EXPECT_EQ(DBL_MIN, double_value);
double_value = 0.0;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 9, &double_value));
EXPECT_EQ(DBL_MAX, double_value);
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 1, 0.0));
double_value = DBL_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 1, &double_value));
EXPECT_EQ(0.0, double_value);
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 9, -0.0));
double_value = DBL_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 9, &double_value));
EXPECT_EQ(-0.0, double_value);
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 9, 1.0));
double_value = DBL_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 9, &double_value));
EXPECT_EQ(1.0, double_value);
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 1, -1.0));
double_value = DBL_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 1, &double_value));
EXPECT_EQ(-1.0, double_value);
}
TEST_CASE(ExternalByteArrayAccess) {
uint8_t data[] = { 0, 11, 22, 33, 44, 55, 66, 77 };
intptr_t data_length = ARRAY_SIZE(data);
Dart_Handle obj = Dart_NewExternalByteArray(data, data_length, NULL, NULL);
EXPECT_VALID(obj);
EXPECT(Dart_IsByteArray(obj));
EXPECT(Dart_IsList(obj));
void* peer = &data; // just a non-NULL value
EXPECT_VALID(Dart_ExternalByteArrayGetPeer(obj, &peer));
EXPECT(peer == NULL);
intptr_t list_length = 0;
EXPECT_VALID(Dart_ListLength(obj, &list_length));
EXPECT_EQ(data_length, list_length);
// Load and check values from underlying array and API.
for (intptr_t i = 0; i < list_length; ++i) {
EXPECT_EQ(11 * i, data[i]);
Dart_Handle elt = Dart_ListGetAt(obj, i);
EXPECT_VALID(elt);
int64_t value = 0;
EXPECT_VALID(Dart_IntegerToInt64(elt, &value));
EXPECT_EQ(data[i], value);
}
// Write values through the underlying array.
for (intptr_t i = 0; i < data_length; ++i) {
data[i] *= 2;
}
// Read them back through the API.
for (intptr_t i = 0; i < list_length; ++i) {
Dart_Handle elt = Dart_ListGetAt(obj, i);
EXPECT_VALID(elt);
int64_t value = 0;
EXPECT_VALID(Dart_IntegerToInt64(elt, &value));
EXPECT_EQ(22 * i, value);
}
// Write values through the API.
for (intptr_t i = 0; i < list_length; ++i) {
Dart_Handle value = Dart_NewInteger(33 * i);
EXPECT_VALID(value);
EXPECT_VALID(Dart_ListSetAt(obj, i, value));
}
// Read them back through the underlying array.
for (intptr_t i = 0; i < data_length; ++i) {
EXPECT_EQ(33 * i, data[i]);
}
}
static void ExternalByteArrayCallbackFinalizer(void* peer) {
*static_cast<int*>(peer) = 42;
}
TEST_CASE(ExternalByteArrayCallback) {
int peer = 0;
{
Dart_EnterScope();
uint8_t data[] = { 1, 2, 3, 4 };
Dart_Handle obj = Dart_NewExternalByteArray(
data,
ARRAY_SIZE(data),
&peer,
ExternalByteArrayCallbackFinalizer);
EXPECT_VALID(obj);
void* api_peer = NULL;
EXPECT_VALID(Dart_ExternalByteArrayGetPeer(obj, &api_peer));
EXPECT_EQ(api_peer, &peer);
Dart_ExitScope();
}
EXPECT(peer == 0);
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT(peer == 0);
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
EXPECT(peer == 42);
}
#endif
// Unit test for entering a scope, creating a local handle and exiting
// the scope.
UNIT_TEST_CASE(EnterExitScope) {
TestIsolateScope __test_isolate__;
Isolate* isolate = Isolate::Current();
EXPECT(isolate != NULL);
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
ApiLocalScope* scope = state->top_scope();
Dart_EnterScope();
{
EXPECT(state->top_scope() != NULL);
DARTSCOPE_NOCHECKS(isolate);
const String& str1 = String::Handle(String::New("Test String"));
Dart_Handle ref = Api::NewHandle(isolate, str1.raw());
String& str2 = String::Handle();
str2 ^= Api::UnwrapHandle(ref);
EXPECT(str1.Equals(str2));
}
Dart_ExitScope();
EXPECT(scope == state->top_scope());
}
// Unit test for creating and deleting persistent handles.
UNIT_TEST_CASE(PersistentHandles) {
const char* kTestString1 = "Test String1";
const char* kTestString2 = "Test String2";
TestCase::CreateTestIsolate();
Isolate* isolate = Isolate::Current();
EXPECT(isolate != NULL);
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
ApiLocalScope* scope = state->top_scope();
Dart_Handle handles[2000];
Dart_EnterScope();
{
DARTSCOPE_NOCHECKS(isolate);
Dart_Handle ref1 = Api::NewHandle(isolate, String::New(kTestString1));
for (int i = 0; i < 1000; i++) {
handles[i] = Dart_NewPersistentHandle(ref1);
}
Dart_EnterScope();
Dart_Handle ref2 = Api::NewHandle(isolate, String::New(kTestString2));
for (int i = 1000; i < 2000; i++) {
handles[i] = Dart_NewPersistentHandle(ref2);
}
for (int i = 500; i < 1500; i++) {
Dart_DeletePersistentHandle(handles[i]);
}
for (int i = 500; i < 1000; i++) {
handles[i] = Dart_NewPersistentHandle(ref2);
}
for (int i = 1000; i < 1500; i++) {
handles[i] = Dart_NewPersistentHandle(ref1);
}
VERIFY_ON_TRANSITION;
Dart_ExitScope();
}
Dart_ExitScope();
{
DARTSCOPE_NOCHECKS(isolate);
for (int i = 0; i < 500; i++) {
String& str = String::Handle();
str ^= Api::UnwrapHandle(handles[i]);
EXPECT(str.Equals(kTestString1));
}
for (int i = 500; i < 1000; i++) {
String& str = String::Handle();
str ^= Api::UnwrapHandle(handles[i]);
EXPECT(str.Equals(kTestString2));
}
for (int i = 1000; i < 1500; i++) {
String& str = String::Handle();
str ^= Api::UnwrapHandle(handles[i]);
EXPECT(str.Equals(kTestString1));
}
for (int i = 1500; i < 2000; i++) {
String& str = String::Handle();
str ^= Api::UnwrapHandle(handles[i]);
EXPECT(str.Equals(kTestString2));
}
}
EXPECT(scope == state->top_scope());
EXPECT_EQ(2000, state->CountPersistentHandles());
Dart_ShutdownIsolate();
}
// Test that we are able to create a persistent handle from a
// persistent handle.
UNIT_TEST_CASE(NewPersistentHandle_FromPersistentHandle) {
TestIsolateScope __test_isolate__;
Isolate* isolate = Isolate::Current();
EXPECT(isolate != NULL);
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
// Start with a known persistent handle.
Dart_Handle obj1 = Dart_True();
EXPECT(state->IsValidPersistentHandle(obj1));
// And use it to allocate a second persistent handle.
Dart_Handle obj2 = Dart_NewPersistentHandle(obj1);
EXPECT(state->IsValidPersistentHandle(obj2));
// Make sure that the value transferred.
EXPECT(Dart_IsBoolean(obj2));
bool value = false;
Dart_Handle result = Dart_BooleanValue(obj2, &value);
EXPECT_VALID(result);
EXPECT(value);
}
// Helper class to ensure new gen GC is triggered without any side effects.
// The normal call to CollectGarbage(Heap::kNew) could potentially trigger
// an old gen collection if there is a promotion failure and this could
// perturb the test.
class GCTestHelper : public AllStatic {
public:
static void CollectNewSpace(Heap::ApiCallbacks api_callbacks) {
bool invoke_api_callbacks = (api_callbacks == Heap::kInvokeApiCallbacks);
Isolate::Current()->heap()->new_space_->Scavenge(invoke_api_callbacks,
"test case");
}
};
// Only ia32 and x64 can run execution tests.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
TEST_CASE(WeakPersistentHandle) {
Dart_Handle weak_new_ref = Dart_Null();
EXPECT(Dart_IsNull(weak_new_ref));
Dart_Handle weak_old_ref = Dart_Null();
EXPECT(Dart_IsNull(weak_old_ref));
{
Dart_EnterScope();
// Create an object in new space.
Dart_Handle new_ref = Dart_NewString("new string");
EXPECT_VALID(new_ref);
// Create an object in old space.
Dart_Handle old_ref;
{
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
old_ref = Api::NewHandle(isolate, String::New("old string", Heap::kOld));
EXPECT_VALID(old_ref);
}
// Create a weak ref to the new space object.
weak_new_ref = Dart_NewWeakPersistentHandle(new_ref, NULL, NULL);
EXPECT_VALID(weak_new_ref);
EXPECT(!Dart_IsNull(weak_new_ref));
// Create a weak ref to the old space object.
weak_old_ref = Dart_NewWeakPersistentHandle(old_ref, NULL, NULL);
EXPECT_VALID(weak_old_ref);
EXPECT(!Dart_IsNull(weak_old_ref));
// Garbage collect new space.
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
// Nothing should be invalidated or cleared.
EXPECT_VALID(new_ref);
EXPECT(!Dart_IsNull(new_ref));
EXPECT_VALID(old_ref);
EXPECT(!Dart_IsNull(old_ref));
EXPECT_VALID(weak_new_ref);
EXPECT(!Dart_IsNull(weak_new_ref));
EXPECT(Dart_IdentityEquals(new_ref, weak_new_ref));
EXPECT_VALID(weak_old_ref);
EXPECT(!Dart_IsNull(weak_old_ref));
EXPECT(Dart_IdentityEquals(old_ref, weak_old_ref));
// Garbage collect old space.
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
// Nothing should be invalidated or cleared.
EXPECT_VALID(new_ref);
EXPECT(!Dart_IsNull(new_ref));
EXPECT_VALID(old_ref);
EXPECT(!Dart_IsNull(old_ref));
EXPECT_VALID(weak_new_ref);
EXPECT(!Dart_IsNull(weak_new_ref));
EXPECT(Dart_IdentityEquals(new_ref, weak_new_ref));
EXPECT_VALID(weak_old_ref);
EXPECT(!Dart_IsNull(weak_old_ref));
EXPECT(Dart_IdentityEquals(old_ref, weak_old_ref));
// Delete local (strong) references.
Dart_ExitScope();
}
// Garbage collect new space again.
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
// Weak ref to new space object should now be cleared.
EXPECT_VALID(weak_new_ref);
EXPECT(Dart_IsNull(weak_new_ref));
EXPECT_VALID(weak_old_ref);
EXPECT(!Dart_IsNull(weak_old_ref));
// Garbage collect old space again.
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
// Weak ref to old space object should now be cleared.
EXPECT_VALID(weak_new_ref);
EXPECT(Dart_IsNull(weak_new_ref));
EXPECT_VALID(weak_old_ref);
EXPECT(Dart_IsNull(weak_old_ref));
Dart_DeletePersistentHandle(weak_new_ref);
Dart_DeletePersistentHandle(weak_old_ref);
// Garbage collect one last time to revisit deleted handles.
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
static void WeakPersistentHandlePeerFinalizer(Dart_Handle handle, void* peer) {
*static_cast<int*>(peer) = 42;
}
TEST_CASE(WeakPersistentHandleCallback) {
Dart_Handle weak_ref = Dart_Null();
EXPECT(Dart_IsNull(weak_ref));
int peer = 0;
{
Dart_EnterScope();
Dart_Handle obj = Dart_NewString("new string");
EXPECT_VALID(obj);
weak_ref = Dart_NewWeakPersistentHandle(obj, &peer,
WeakPersistentHandlePeerFinalizer);
Dart_ExitScope();
}
EXPECT_VALID(weak_ref);
EXPECT(peer == 0);
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT(peer == 0);
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
EXPECT(peer == 42);
Dart_DeletePersistentHandle(weak_ref);
}
TEST_CASE(WeakPersistentHandleNoCallback) {
Dart_Handle weak_ref = Dart_Null();
EXPECT(Dart_IsNull(weak_ref));
int peer = 0;
{
Dart_EnterScope();
Dart_Handle obj = Dart_NewString("new string");
EXPECT_VALID(obj);
weak_ref = Dart_NewWeakPersistentHandle(obj, &peer,
WeakPersistentHandlePeerFinalizer);
Dart_ExitScope();
}
// A finalizer is not invoked on a deleted handle. Therefore, the
// peer value should not change after the referent is collected.
Dart_DeletePersistentHandle(weak_ref);
EXPECT_VALID(weak_ref);
EXPECT(peer == 0);
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT(peer == 0);
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
EXPECT(peer == 0);
}
UNIT_TEST_CASE(WeakPersistentHandlesCallbackShutdown) {
TestCase::CreateTestIsolate();
Dart_EnterScope();
Dart_Handle ref = Dart_True();
int peer = 1234;
Dart_NewWeakPersistentHandle(ref,
&peer,
WeakPersistentHandlePeerFinalizer);
Dart_ShutdownIsolate();
EXPECT(peer == 42);
}
TEST_CASE(ObjectGroups) {
Dart_Handle strong = Dart_Null();
EXPECT(Dart_IsNull(strong));
Dart_Handle weak1 = Dart_Null();
EXPECT(Dart_IsNull(weak1));
Dart_Handle weak2 = Dart_Null();
EXPECT(Dart_IsNull(weak2));
Dart_Handle weak3 = Dart_Null();
EXPECT(Dart_IsNull(weak3));
Dart_Handle weak4 = Dart_Null();
EXPECT(Dart_IsNull(weak4));
Dart_EnterScope();
{
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
strong = Dart_NewPersistentHandle(
Api::NewHandle(isolate, String::New("strongly reachable", Heap::kOld)));
EXPECT_VALID(strong);
EXPECT(!Dart_IsNull(strong));
weak1 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kOld)),
NULL, NULL);
EXPECT_VALID(weak1);
EXPECT(!Dart_IsNull(weak1));
weak2 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kOld)),
NULL, NULL);
EXPECT_VALID(weak2);
EXPECT(!Dart_IsNull(weak2));
weak3 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kOld)),
NULL, NULL);
EXPECT_VALID(weak3);
EXPECT(!Dart_IsNull(weak3));
weak4 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 4", Heap::kOld)),
NULL, NULL);
EXPECT_VALID(weak4);
EXPECT(!Dart_IsNull(weak4));
}
Dart_ExitScope();
EXPECT_VALID(strong);
EXPECT_VALID(weak1);
EXPECT_VALID(weak2);
EXPECT_VALID(weak3);
EXPECT_VALID(weak4);
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
// New space collection should not affect old space objects
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(!Dart_IsNull(weak3));
EXPECT(!Dart_IsNull(weak4));
{
Dart_Handle array1[] = { weak1, strong };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
Dart_Handle array2[] = { weak2, weak1 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
Dart_Handle array3[] = { weak3, weak2 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array3, ARRAY_SIZE(array3),
array3, ARRAY_SIZE(array3)));
Dart_Handle array4[] = { weak4, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array4, ARRAY_SIZE(array4),
array4, ARRAY_SIZE(array4)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
// All weak references should be preserved.
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(!Dart_IsNull(weak3));
EXPECT(!Dart_IsNull(weak4));
{
Dart_Handle array1[] = { weak1, strong };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
Dart_Handle array2[] = { weak2, weak1 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
Dart_Handle array3[] = { weak2 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array3, ARRAY_SIZE(array3),
array3, ARRAY_SIZE(array3)));
// Strong reference to weak3 to retain weak3 and weak4.
Dart_Handle weak3_strong_ref = Dart_NewPersistentHandle(weak3);
EXPECT_VALID(weak3_strong_ref);
Dart_Handle array4[] = { weak4, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array4, ARRAY_SIZE(array4),
array4, ARRAY_SIZE(array4)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
// Delete strong reference to weak3.
Dart_DeletePersistentHandle(weak3_strong_ref);
}
// All weak references should be preserved.
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(!Dart_IsNull(weak3));
EXPECT(!Dart_IsNull(weak4));
{
Dart_Handle array1[] = { weak1, strong };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
Dart_Handle array2[] = { weak2, weak1 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
Dart_Handle array3[] = { weak2 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array3, ARRAY_SIZE(array3),
array3, ARRAY_SIZE(array3)));
Dart_Handle array4[] = { weak4, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array4, ARRAY_SIZE(array4),
array4, ARRAY_SIZE(array4)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
// Only weak1 and weak2 should be preserved.
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(Dart_IsNull(weak3));
EXPECT(Dart_IsNull(weak4));
{
Dart_Handle array1[] = { weak1, strong };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
// weak3 is cleared so weak2 is unreferenced and should be cleared
Dart_Handle array2[] = { weak2, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
// Only weak1 should be preserved, weak3 should not preserve weak2.
EXPECT(!Dart_IsNull(weak1));
EXPECT(Dart_IsNull(weak2));
EXPECT(Dart_IsNull(weak3)); // was cleared, should remain cleared
EXPECT(Dart_IsNull(weak4)); // was cleared, should remain cleared
{
// weak{2,3,4} are cleared and should have no effect on weak1
Dart_Handle array1[] = { strong, weak2, weak3, weak4 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
// weak1 is weakly reachable and should be cleared
Dart_Handle array2[] = { weak1 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
// All weak references should now be cleared.
EXPECT(Dart_IsNull(weak1));
EXPECT(Dart_IsNull(weak2));
EXPECT(Dart_IsNull(weak3));
EXPECT(Dart_IsNull(weak4));
}
TEST_CASE(PrologueWeakPersistentHandles) {
Dart_Handle old_pwph = Dart_Null();
EXPECT(Dart_IsNull(old_pwph));
Dart_Handle new_pwph = Dart_Null();
EXPECT(Dart_IsNull(new_pwph));
Dart_EnterScope();
{
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
new_pwph = Dart_NewPrologueWeakPersistentHandle(
Api::NewHandle(isolate,
String::New("new space prologue weak", Heap::kNew)),
NULL, NULL);
EXPECT_VALID(new_pwph);
EXPECT(!Dart_IsNull(new_pwph));
old_pwph = Dart_NewPrologueWeakPersistentHandle(
Api::NewHandle(isolate,
String::New("old space prologue weak", Heap::kOld)),
NULL, NULL);
EXPECT_VALID(old_pwph);
EXPECT(!Dart_IsNull(old_pwph));
}
Dart_ExitScope();
EXPECT_VALID(new_pwph);
EXPECT(!Dart_IsNull(new_pwph));
EXPECT(Dart_IsPrologueWeakPersistentHandle(new_pwph));
EXPECT_VALID(old_pwph);
EXPECT(!Dart_IsNull(old_pwph));
EXPECT(Dart_IsPrologueWeakPersistentHandle(old_pwph));
// Garbage collect new space without invoking API callbacks.
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
// Both prologue weak handles should be preserved.
EXPECT(!Dart_IsNull(new_pwph));
EXPECT(!Dart_IsNull(old_pwph));
// Garbage collect old space without invoking API callbacks.
Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
Heap::kIgnoreApiCallbacks);
// Both prologue weak handles should be preserved.
EXPECT(!Dart_IsNull(new_pwph));
EXPECT(!Dart_IsNull(old_pwph));
// Garbage collect new space invoking API callbacks.
GCTestHelper::CollectNewSpace(Heap::kInvokeApiCallbacks);
// The prologue weak handle with a new space referent should now be
// cleared. The old space referent should be preserved.
EXPECT(Dart_IsNull(new_pwph));
EXPECT(!Dart_IsNull(old_pwph));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
Heap::kInvokeApiCallbacks);
// The prologue weak handle with an old space referent should now be
// cleared. The new space referent should remain cleared.
EXPECT(Dart_IsNull(new_pwph));
EXPECT(Dart_IsNull(old_pwph));
}
TEST_CASE(ImplicitReferencesOldSpace) {
Dart_Handle strong = Dart_Null();
EXPECT(Dart_IsNull(strong));
Dart_Handle weak1 = Dart_Null();
EXPECT(Dart_IsNull(weak1));
Dart_Handle weak2 = Dart_Null();
EXPECT(Dart_IsNull(weak2));
Dart_Handle weak3 = Dart_Null();
EXPECT(Dart_IsNull(weak3));
Dart_EnterScope();
{
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
strong = Dart_NewPersistentHandle(
Api::NewHandle(isolate, String::New("strongly reachable", Heap::kOld)));
EXPECT(!Dart_IsNull(strong));
EXPECT_VALID(strong);
weak1 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kOld)),
NULL, NULL);
EXPECT(!Dart_IsNull(weak1));
EXPECT_VALID(weak1);
weak2 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kOld)),
NULL, NULL);
EXPECT(!Dart_IsNull(weak2));
EXPECT_VALID(weak2);
weak3 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kOld)),
NULL, NULL);
EXPECT(!Dart_IsNull(weak3));
EXPECT_VALID(weak3);
}
Dart_ExitScope();
EXPECT_VALID(strong);
EXPECT_VALID(weak1);
EXPECT_VALID(weak2);
EXPECT_VALID(weak3);
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
// New space collection should not affect old space objects
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(!Dart_IsNull(weak3));
// A strongly referenced key should preserve all the values.
{
Dart_Handle keys[] = { strong };
Dart_Handle values[] = { weak1, weak2, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(keys, ARRAY_SIZE(keys),
values, ARRAY_SIZE(values)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
// All weak references should be preserved.
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(!Dart_IsNull(weak3));
// Key membership does not imply a strong reference.
{
Dart_Handle keys[] = { strong, weak3 };
Dart_Handle values[] = { weak1, weak2 };
EXPECT_VALID(Dart_NewWeakReferenceSet(keys, ARRAY_SIZE(keys),
values, ARRAY_SIZE(values)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
// All weak references except weak3 should be preserved.
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(Dart_IsNull(weak3));
}
TEST_CASE(ImplicitReferencesNewSpace) {
Dart_Handle strong = Dart_Null();
EXPECT(Dart_IsNull(strong));
Dart_Handle weak1 = Dart_Null();
EXPECT(Dart_IsNull(weak1));
Dart_Handle weak2 = Dart_Null();
EXPECT(Dart_IsNull(weak2));
Dart_Handle weak3 = Dart_Null();
EXPECT(Dart_IsNull(weak3));
Dart_EnterScope();
{
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
strong = Dart_NewPersistentHandle(
Api::NewHandle(isolate, String::New("strongly reachable", Heap::kNew)));
EXPECT(!Dart_IsNull(strong));
EXPECT_VALID(strong);
weak1 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kNew)),
NULL, NULL);
EXPECT(!Dart_IsNull(weak1));
EXPECT_VALID(weak1);
weak2 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kNew)),
NULL, NULL);
EXPECT(!Dart_IsNull(weak2));
EXPECT_VALID(weak2);
weak3 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kNew)),
NULL, NULL);
EXPECT(!Dart_IsNull(weak3));
EXPECT_VALID(weak3);
}
Dart_ExitScope();
EXPECT_VALID(strong);
EXPECT_VALID(weak1);
EXPECT_VALID(weak2);
EXPECT_VALID(weak3);
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
// Old space collection should not affect old space objects.
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(!Dart_IsNull(weak3));
// A strongly referenced key should preserve all the values.
{
Dart_Handle keys[] = { strong };
Dart_Handle values[] = { weak1, weak2, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(keys, ARRAY_SIZE(keys),
values, ARRAY_SIZE(values)));
GCTestHelper::CollectNewSpace(Heap::kInvokeApiCallbacks);
}
// All weak references should be preserved.
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(!Dart_IsNull(weak3));
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
// No weak references should be preserved.
EXPECT(Dart_IsNull(weak1));
EXPECT(Dart_IsNull(weak2));
EXPECT(Dart_IsNull(weak3));
}
static int global_prologue_callback_status;
static void PrologueCallbackTimes2() {
global_prologue_callback_status *= 2;
}
static void PrologueCallbackTimes3() {
global_prologue_callback_status *= 3;
}
static int global_epilogue_callback_status;
static void EpilogueCallbackTimes4() {
global_epilogue_callback_status *= 4;
}
static void EpilogueCallbackTimes5() {
global_epilogue_callback_status *= 5;
}
TEST_CASE(AddGarbageCollectionCallbacks) {
// Add a prologue callback.
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes2));
// Add the same prologue callback again. This is an error.
EXPECT(Dart_IsError(Dart_AddGcPrologueCallback(&PrologueCallbackTimes2)));
// Add another prologue callback.
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes3));
// Add the same prologue callback again. This is an error.
EXPECT(Dart_IsError(Dart_AddGcPrologueCallback(&PrologueCallbackTimes3)));
// Add an epilogue callback.
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes4));
// Add the same epilogue callback again. This is an error.
EXPECT(Dart_IsError(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes4)));
// Add annother epilogue callback.
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes5));
// Add the same epilogue callback again. This is an error.
EXPECT(Dart_IsError(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes5)));
}
TEST_CASE(RemoveGarbageCollectionCallbacks) {
// Remove a prologue callback that has not been added. This is an error.
EXPECT(Dart_IsError(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes2)));
// Add a prologue callback.
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes2));
// Remove a prologue callback.
EXPECT_VALID(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes2));
// Remove a prologue callback again. This is an error.
EXPECT(Dart_IsError(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes2)));
// Add two prologue callbacks.
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes2));
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes3));
// Remove two prologue callbacks.
EXPECT_VALID(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes3));
EXPECT_VALID(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes2));
// Remove epilogue callbacks again. This is an error.
EXPECT(Dart_IsError(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes4)));
EXPECT(Dart_IsError(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes5)));
// Remove a epilogue callback that has not been added. This is an error.
EXPECT(Dart_IsError(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes5)));
// Add a epilogue callback.
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes4));
// Remove a epilogue callback.
EXPECT_VALID(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes4));
// Remove a epilogue callback again. This is an error.
EXPECT(Dart_IsError(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes4)));
// Add two epilogue callbacks.
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes4));
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes5));
// Remove two epilogue callbacks.
EXPECT_VALID(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes5));
EXPECT_VALID(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes4));
// Remove epilogue callbacks again. This is an error.
EXPECT(Dart_IsError(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes4)));
EXPECT(Dart_IsError(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes5)));
}
TEST_CASE(SingleGarbageCollectionCallback) {
// Add a prologue callback.
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes2));
// Garbage collect new space ignoring callbacks. This should not
// invoke the prologue callback. No status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
EXPECT_EQ(3, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Garbage collect new space invoking callbacks. This should
// invoke the prologue callback. No status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
GCTestHelper::CollectNewSpace(Heap::kInvokeApiCallbacks);
EXPECT_EQ(6, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Garbage collect old space ignoring callbacks. This should invoke
// the prologue callback. The prologue status value should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
Heap::kIgnoreApiCallbacks);
EXPECT_EQ(3, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Garbage collect old space. This should invoke the prologue
// callback. The prologue status value should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(6, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Garbage collect old space again. Callbacks are persistent so the
// prolog status value should change again.
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(12, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Add an epilogue callback.
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes4));
// Garbage collect new space. This should not invoke the prologue
// or the epilogue callback. No status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
EXPECT_EQ(3, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Garbage collect new space. This should invoke the prologue and
// the epilogue callback. The prologue and epilogue status values
// should change.
GCTestHelper::CollectNewSpace(Heap::kInvokeApiCallbacks);
EXPECT_EQ(6, global_prologue_callback_status);
EXPECT_EQ(28, global_epilogue_callback_status);
// Garbage collect old space. This should invoke the prologue and
// the epilogue callbacks. The prologue and epilogue status values
// should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(6, global_prologue_callback_status);
EXPECT_EQ(28, global_epilogue_callback_status);
// Garbage collect old space again without invoking callbacks.
// Nothing should change.
Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
Heap::kIgnoreApiCallbacks);
EXPECT_EQ(6, global_prologue_callback_status);
EXPECT_EQ(28, global_epilogue_callback_status);
// Garbage collect old space again. Callbacks are persistent so the
// prologue and epilogue status values should change again.
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(12, global_prologue_callback_status);
EXPECT_EQ(112, global_epilogue_callback_status);
// Remove the prologue and epilogue callbacks
EXPECT_VALID(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes2));
EXPECT_VALID(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes4));
// Garbage collect old space. No callbacks should be invoked. No
// status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(3, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
}
TEST_CASE(MultipleGarbageCollectionCallbacks) {
// Add prologue callbacks.
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes2));
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes3));
// Add an epilogue callback.
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes4));
// Garbage collect new space. This should not invoke the prologue
// or epilogue callbacks. No status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
EXPECT_EQ(3, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Garbage collect old space. This should invoke both prologue
// callbacks and the epilogue callback. The prologue and epilogue
// status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(18, global_prologue_callback_status);
EXPECT_EQ(28, global_epilogue_callback_status);
// Add another GC epilogue callback.
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes5));
// Garbage collect old space. This should invoke both prologue
// callbacks and both epilogue callbacks. The prologue and epilogue
// status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(18, global_prologue_callback_status);
EXPECT_EQ(140, global_epilogue_callback_status);
// Remove an epilogue callback.
EXPECT_VALID(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes4));
// Garbage collect old space. This should invoke both prologue
// callbacks and the remaining epilogue callback. The prologue and
// epilogue status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(18, global_prologue_callback_status);
EXPECT_EQ(35, global_epilogue_callback_status);
// Remove the remaining epilogue callback.
EXPECT_VALID(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes5));
// Garbage collect old space. This should invoke both prologue
// callbacks. The prologue status value should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(18, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Remove a prologue callback.
EXPECT_VALID(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes3));
// Garbage collect old space. This should invoke the remaining
// prologue callback. The prologue status value should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(6, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Remove the remaining prologue callback.
EXPECT_VALID(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes2));
// Garbage collect old space. No callbacks should be invoked. No
// status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(3, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
}
#endif
// Unit test for creating multiple scopes and local handles within them.
// Ensure that the local handles get all cleaned out when exiting the
// scope.
UNIT_TEST_CASE(LocalHandles) {
TestCase::CreateTestIsolate();
Isolate* isolate = Isolate::Current();
EXPECT(isolate != NULL);
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
ApiLocalScope* scope = state->top_scope();
Dart_Handle handles[300];
{
DARTSCOPE_NOCHECKS(isolate);
Smi& val = Smi::Handle();
// Start a new scope and allocate some local handles.
Dart_EnterScope();
for (int i = 0; i < 100; i++) {
handles[i] = Api::NewHandle(isolate, Smi::New(i));
}
EXPECT_EQ(100, state->CountLocalHandles());
for (int i = 0; i < 100; i++) {
val ^= Api::UnwrapHandle(handles[i]);
EXPECT_EQ(i, val.Value());
}
// Start another scope and allocate some more local handles.
{
Dart_EnterScope();
for (int i = 100; i < 200; i++) {
handles[i] = Api::NewHandle(isolate, Smi::New(i));
}
EXPECT_EQ(200, state->CountLocalHandles());
for (int i = 100; i < 200; i++) {
val ^= Api::UnwrapHandle(handles[i]);
EXPECT_EQ(i, val.Value());
}
// Start another scope and allocate some more local handles.
{
Dart_EnterScope();
for (int i = 200; i < 300; i++) {
handles[i] = Api::NewHandle(isolate, Smi::New(i));
}
EXPECT_EQ(300, state->CountLocalHandles());
for (int i = 200; i < 300; i++) {
val ^= Api::UnwrapHandle(handles[i]);
EXPECT_EQ(i, val.Value());
}
EXPECT_EQ(300, state->CountLocalHandles());
VERIFY_ON_TRANSITION;
Dart_ExitScope();
}
EXPECT_EQ(200, state->CountLocalHandles());
Dart_ExitScope();
}
EXPECT_EQ(100, state->CountLocalHandles());
Dart_ExitScope();
}
EXPECT_EQ(0, state->CountLocalHandles());
EXPECT(scope == state->top_scope());
Dart_ShutdownIsolate();
}
// Unit test for creating multiple scopes and allocating objects in the
// zone for the scope. Ensure that the memory is freed when the scope
// exits.
UNIT_TEST_CASE(LocalZoneMemory) {
TestCase::CreateTestIsolate();
Isolate* isolate = Isolate::Current();
EXPECT(isolate != NULL);
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
ApiLocalScope* scope = state->top_scope();
{
// Start a new scope and allocate some memory.
Dart_EnterScope();
for (int i = 0; i < 100; i++) {
Dart_ScopeAllocate(16);
}
EXPECT_EQ(1600, state->ZoneSizeInBytes());
// Start another scope and allocate some more memory.
{
Dart_EnterScope();
for (int i = 0; i < 100; i++) {
Dart_ScopeAllocate(16);
}
EXPECT_EQ(3200, state->ZoneSizeInBytes());
{
// Start another scope and allocate some more memory.
{
Dart_EnterScope();
for (int i = 0; i < 200; i++) {
Dart_ScopeAllocate(16);
}
EXPECT_EQ(6400, state->ZoneSizeInBytes());
Dart_ExitScope();
}
}
EXPECT_EQ(3200, state->ZoneSizeInBytes());
Dart_ExitScope();
}
EXPECT_EQ(1600, state->ZoneSizeInBytes());
Dart_ExitScope();
}
EXPECT_EQ(0, state->ZoneSizeInBytes());
EXPECT(scope == state->top_scope());
Dart_ShutdownIsolate();
}
UNIT_TEST_CASE(Isolates) {
// This test currently assumes that the Dart_Isolate type is an opaque
// representation of Isolate*.
Dart_Isolate iso_1 = TestCase::CreateTestIsolate();
EXPECT_EQ(iso_1, Api::CastIsolate(Isolate::Current()));
Dart_Isolate isolate = Dart_CurrentIsolate();
EXPECT_EQ(iso_1, isolate);
Dart_ExitIsolate();
EXPECT(NULL == Dart_CurrentIsolate());
Dart_Isolate iso_2 = TestCase::CreateTestIsolate();
EXPECT_EQ(iso_2, Dart_CurrentIsolate());
Dart_ExitIsolate();
EXPECT(NULL == Dart_CurrentIsolate());
Dart_EnterIsolate(iso_2);
EXPECT_EQ(iso_2, Dart_CurrentIsolate());
Dart_ShutdownIsolate();
EXPECT(NULL == Dart_CurrentIsolate());
Dart_EnterIsolate(iso_1);
EXPECT_EQ(iso_1, Dart_CurrentIsolate());
Dart_ShutdownIsolate();
EXPECT(NULL == Dart_CurrentIsolate());
}
UNIT_TEST_CASE(CurrentIsolateData) {
intptr_t mydata = 12345;
char* err;
Dart_Isolate isolate =
Dart_CreateIsolate(NULL, NULL, NULL,
reinterpret_cast<void*>(mydata),
&err);
EXPECT(isolate != NULL);
EXPECT_EQ(mydata, reinterpret_cast<intptr_t>(Dart_CurrentIsolateData()));
Dart_ShutdownIsolate();
}
TEST_CASE(DebugName) {
Dart_Handle debug_name = Dart_DebugName();
EXPECT_VALID(debug_name);
EXPECT(Dart_IsString(debug_name));
}
static void MyMessageNotifyCallback(Dart_Isolate dest_isolate) {
}
UNIT_TEST_CASE(SetMessageCallbacks) {
Dart_Isolate dart_isolate = TestCase::CreateTestIsolate();
Dart_SetMessageNotifyCallback(&MyMessageNotifyCallback);
Isolate* isolate = reinterpret_cast<Isolate*>(dart_isolate);
EXPECT_EQ(&MyMessageNotifyCallback, isolate->message_notify_callback());
Dart_ShutdownIsolate();
}
// Only ia32 and x64 can run execution tests.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
TEST_CASE(ClassBasics) {
const char* kScriptChars =
"class MyClass {\n"
"}\n"
"class MyDefault {\n"
"}\n"
"interface MyInterface default MyDefault {\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("MyClass"));
Dart_Handle interface = Dart_GetClass(lib, Dart_NewString("MyInterface"));
// Test Dart_IsClass and Dart_IsInterface.
EXPECT(Dart_IsClass(cls));
EXPECT(!Dart_IsClass(interface));
EXPECT(!Dart_IsClass(Dart_True()));
EXPECT(!Dart_IsInterface(cls));
EXPECT(Dart_IsInterface(interface));
EXPECT(!Dart_IsInterface(Dart_True()));
EXPECT(!Dart_IsInterface(cls));
EXPECT(Dart_IsInterface(interface));
EXPECT(!Dart_IsInterface(Dart_True()));
// Test Dart_ClassName
Dart_Handle cls_name = Dart_ClassName(cls);
EXPECT_VALID(cls_name);
const char* cls_name_cstr = "";
EXPECT_VALID(Dart_StringToCString(cls_name, &cls_name_cstr));
EXPECT_STREQ("MyClass", cls_name_cstr);
cls_name = Dart_ClassName(interface);
EXPECT_VALID(cls_name);
cls_name_cstr = "";
EXPECT_VALID(Dart_StringToCString(cls_name, &cls_name_cstr));
EXPECT_STREQ("MyInterface", cls_name_cstr);
EXPECT_ERROR(Dart_ClassName(Dart_True()),
"Dart_ClassName expects argument 'clazz' to be of type Class.");
EXPECT_ERROR(Dart_ClassName(Dart_NewApiError("MyError")), "MyError");
// Test Dart_ClassGetLibrary
Dart_Handle cls_lib = Dart_ClassGetLibrary(cls);
Dart_Handle cls_lib_name = Dart_LibraryName(cls_lib);
EXPECT_VALID(cls_lib_name);
const char* cls_lib_name_cstr = "";
EXPECT_VALID(Dart_StringToCString(cls_lib_name, &cls_lib_name_cstr));
EXPECT_STREQ(TestCase::url(), cls_lib_name_cstr);
EXPECT_ERROR(
Dart_ClassGetLibrary(Dart_True()),
"Dart_ClassGetLibrary expects argument 'clazz' to be of type Class.");
EXPECT_ERROR(Dart_ClassGetLibrary(Dart_NewApiError("MyError")), "MyError");
Dart_Handle dflt = Dart_ClassGetDefault(interface);
EXPECT_VALID(dflt);
EXPECT(Dart_IsClass(dflt));
Dart_Handle dflt_name = Dart_ClassName(dflt);
EXPECT_VALID(dflt_name);
const char* dflt_name_cstr = "";
EXPECT_VALID(Dart_StringToCString(dflt_name, &dflt_name_cstr));
EXPECT_STREQ("MyDefault", dflt_name_cstr);
EXPECT(Dart_IsNull(Dart_ClassGetDefault(cls)));
EXPECT_ERROR(
Dart_ClassGetDefault(Dart_True()),
"Dart_ClassGetDefault expects argument 'clazz' to be of type Class.");
EXPECT_ERROR(Dart_ClassGetDefault(Dart_NewApiError("MyError")), "MyError");
}
TEST_CASE(ClassTypedefsEtc) {
const char* kScriptChars =
"class SomeClass {\n"
"}\n"
"typedef void SomeHandler(String a);\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(lib);
Dart_Handle normal_cls = Dart_GetClass(lib, Dart_NewString("SomeClass"));
EXPECT_VALID(normal_cls);
Dart_Handle typedef_cls = Dart_GetClass(lib, Dart_NewString("SomeHandler"));
EXPECT_VALID(typedef_cls);
EXPECT(Dart_IsClass(normal_cls));
EXPECT(!Dart_ClassIsTypedef(normal_cls));
EXPECT(!Dart_ClassIsFunctionType(normal_cls));
EXPECT(Dart_IsClass(typedef_cls));
EXPECT(Dart_ClassIsTypedef(typedef_cls));
EXPECT(!Dart_ClassIsFunctionType(typedef_cls));
// Exercise the typedef class api.
Dart_Handle functype_cls = Dart_ClassGetTypedefReferent(typedef_cls);
EXPECT_VALID(functype_cls);
// Pass the wrong class kind to Dart_ClassGetTypedefReferent
EXPECT_ERROR(Dart_ClassGetTypedefReferent(normal_cls),
"class 'SomeClass' is not a typedef class.");
EXPECT(Dart_IsClass(functype_cls));
EXPECT(!Dart_ClassIsTypedef(functype_cls));
EXPECT(Dart_ClassIsFunctionType(functype_cls));
// Exercise the function type class.
Dart_Handle sig_func = Dart_ClassGetFunctionTypeSignature(functype_cls);
EXPECT_VALID(sig_func);
EXPECT(Dart_IsFunction(sig_func));
int64_t fixed_params = -1;
int64_t opt_params = -1;
EXPECT_VALID(
Dart_FunctionParameterCounts(sig_func, &fixed_params, &opt_params));
EXPECT_EQ(1, fixed_params);
EXPECT_EQ(0, opt_params);
// Pass the wrong class kind to Dart_ClassGetFunctionTypeSignature
EXPECT_ERROR(Dart_ClassGetFunctionTypeSignature(normal_cls),
"class 'SomeClass' is not a function-type class.");
}
#define CHECK_INTERFACE(handle, name) \
{ \
Dart_Handle tmp = (handle); \
EXPECT_VALID(tmp); \
EXPECT(Dart_IsInterface(tmp)); \
Dart_Handle intf_name = Dart_ClassName(tmp); \
EXPECT_VALID(intf_name); \
const char* intf_name_cstr = ""; \
EXPECT_VALID(Dart_StringToCString(intf_name, &intf_name_cstr)); \
EXPECT_STREQ((name), intf_name_cstr); \
}
TEST_CASE(ClassGetInterfaces) {
const char* kScriptChars =
"class MyClass0 {\n"
"}\n"
"\n"
"class MyClass1 implements MyInterface1 {\n"
"}\n"
"\n"
"class MyClass2 implements MyInterface0, MyInterface1 {\n"
"}\n"
"\n"
"interface MyInterface0 {\n"
"}\n"
"\n"
"interface MyInterface1 extends MyInterface0 {\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle cls0 = Dart_GetClass(lib, Dart_NewString("MyClass0"));
Dart_Handle cls1 = Dart_GetClass(lib, Dart_NewString("MyClass1"));
Dart_Handle cls2 = Dart_GetClass(lib, Dart_NewString("MyClass2"));
Dart_Handle intf0 = Dart_GetClass(lib, Dart_NewString("MyInterface0"));
Dart_Handle intf1 = Dart_GetClass(lib, Dart_NewString("MyInterface1"));
intptr_t len = -1;
EXPECT_VALID(Dart_ClassGetInterfaceCount(cls0, &len));
EXPECT_EQ(0, len);
EXPECT_ERROR(Dart_ClassGetInterfaceAt(cls0, 0),
"Dart_ClassGetInterfaceAt: argument 'index' out of bounds");
len = -1;
EXPECT_VALID(Dart_ClassGetInterfaceCount(cls1, &len));
EXPECT_EQ(1, len);
CHECK_INTERFACE(Dart_ClassGetInterfaceAt(cls1, 0), "MyInterface1");
EXPECT_ERROR(Dart_ClassGetInterfaceAt(cls1, -1),
"Dart_ClassGetInterfaceAt: argument 'index' out of bounds");
EXPECT_ERROR(Dart_ClassGetInterfaceAt(cls1, 1),
"Dart_ClassGetInterfaceAt: argument 'index' out of bounds");
len = -1;
EXPECT_VALID(Dart_ClassGetInterfaceCount(cls2, &len));
EXPECT_EQ(2, len);
// TODO(turnidge): The test relies on the ordering here. Sort this.
CHECK_INTERFACE(Dart_ClassGetInterfaceAt(cls2, 0), "MyInterface0");
CHECK_INTERFACE(Dart_ClassGetInterfaceAt(cls2, 1), "MyInterface1");
len = -1;
EXPECT_VALID(Dart_ClassGetInterfaceCount(intf0, &len));
EXPECT_EQ(0, len);
len = -1;
EXPECT_VALID(Dart_ClassGetInterfaceCount(intf1, &len));
EXPECT_EQ(1, len);
CHECK_INTERFACE(Dart_ClassGetInterfaceAt(intf1, 0), "MyInterface0");
// Error cases.
EXPECT_ERROR(Dart_ClassGetInterfaceCount(Dart_True(), &len),
"Dart_ClassGetInterfaceCount expects argument 'clazz' to be of "
"type Class.");
EXPECT_ERROR(Dart_ClassGetInterfaceCount(Dart_NewApiError("MyError"), &len),
"MyError");
}
static void TestFieldOk(Dart_Handle container,
Dart_Handle name,
bool final,
const char* initial_value) {
Dart_Handle result;
// Make sure we have the right initial value.
result = Dart_GetField(container, name);
EXPECT_VALID(result);
const char* value = "";
EXPECT_VALID(Dart_StringToCString(result, &value));
EXPECT_STREQ(initial_value, value);
// Use a unique expected value.
static int counter = 0;
char buffer[256];
OS::SNPrint(buffer, 256, "Expected%d", ++counter);
// Try to change the field value.
result = Dart_SetField(container, name, Dart_NewString(buffer));
if (final) {
EXPECT(Dart_IsError(result));
} else {
EXPECT_VALID(result);
}
// Make sure we have the right final value.
result = Dart_GetField(container, name);
EXPECT_VALID(result);
EXPECT_VALID(Dart_StringToCString(result, &value));
if (final) {
EXPECT_STREQ(initial_value, value);
} else {
EXPECT_STREQ(buffer, value);
}
}
static void TestFieldNotFound(Dart_Handle container,
Dart_Handle name) {
EXPECT(Dart_IsError(Dart_GetField(container, name)));
EXPECT(Dart_IsError(Dart_SetField(container, name, Dart_Null())));
}
TEST_CASE(FieldAccess) {
const char* kScriptChars =
"class BaseFields {\n"
" BaseFields()\n"
" : this.inherited_fld = 'inherited' {\n"
" }\n"
" var inherited_fld;\n"
" static var non_inherited_fld;\n"
"}\n"
"\n"
"class Fields extends BaseFields {\n"
" Fields()\n"
" : this.instance_fld = 'instance',\n"
" this._instance_fld = 'hidden instance',\n"
" this.final_instance_fld = 'final instance',\n"
" this._final_instance_fld = 'hidden final instance' {\n"
" instance_getset_fld = 'instance getset';\n"
" _instance_getset_fld = 'hidden instance getset';\n"
" }\n"
"\n"
" static Init() {\n"
" static_fld = 'static';\n"
" _static_fld = 'hidden static';\n"
" static_getset_fld = 'static getset';\n"
" _static_getset_fld = 'hidden static getset';\n"
" }\n"
"\n"
" var instance_fld;\n"
" var _instance_fld;\n"
" final final_instance_fld;\n"
" final _final_instance_fld;\n"
" static var static_fld;\n"
" static var _static_fld;\n"
" static const const_static_fld = 'const static';\n"
" static const _const_static_fld = 'hidden const static';\n"
"\n"
" get instance_getset_fld { return _gs_fld1; }\n"
" void set instance_getset_fld(var value) { _gs_fld1 = value; }\n"
" get _instance_getset_fld { return _gs_fld2; }\n"
" void set _instance_getset_fld(var value) { _gs_fld2 = value; }\n"
" var _gs_fld1;\n"
" var _gs_fld2;\n"
"\n"
" static get static_getset_fld { return _gs_fld3; }\n"
" static void set static_getset_fld(var value) { _gs_fld3 = value; }\n"
" static get _static_getset_fld { return _gs_fld4; }\n"
" static void set _static_getset_fld(var value) { _gs_fld4 = value; }\n"
" static var _gs_fld3;\n"
" static var _gs_fld4;\n"
"}\n"
"var top_fld;\n"
"var _top_fld;\n"
"const const_top_fld = 'const top';\n"
"const _const_top_fld = 'hidden const top';\n"
"\n"
"get top_getset_fld { return _gs_fld5; }\n"
"void set top_getset_fld(var value) { _gs_fld5 = value; }\n"
"get _top_getset_fld { return _gs_fld6; }\n"
"void set _top_getset_fld(var value) { _gs_fld6 = value; }\n"
"var _gs_fld5;\n"
"var _gs_fld6;\n"
"\n"
"Fields test() {\n"
" Fields.Init();\n"
" top_fld = 'top';\n"
" _top_fld = 'hidden top';\n"
" top_getset_fld = 'top getset';\n"
" _top_getset_fld = 'hidden top getset';\n"
" return new Fields();\n"
"}\n";
const char* kImportedScriptChars =
"#library('library_name');\n"
"var imported_fld = 'imported';\n"
"var _imported_fld = 'hidden imported';\n"
"get imported_getset_fld { return _gs_fld1; }\n"
"void set imported_getset_fld(var value) { _gs_fld1 = value; }\n"
"get _imported_getset_fld { return _gs_fld2; }\n"
"void set _imported_getset_fld(var value) { _gs_fld2 = value; }\n"
"var _gs_fld1;\n"
"var _gs_fld2;\n"
"void test2() {\n"
" imported_getset_fld = 'imported getset';\n"
" _imported_getset_fld = 'hidden imported getset';\n"
"}\n";
// Shared setup.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("Fields"));
EXPECT_VALID(cls);
Dart_Handle instance = Dart_Invoke(lib, Dart_NewString("test"), 0, NULL);
EXPECT_VALID(instance);
Dart_Handle name;
// Load imported lib.
Dart_Handle url = Dart_NewString("library_url");
Dart_Handle source = Dart_NewString(kImportedScriptChars);
Dart_Handle imported_lib = Dart_LoadLibrary(url, source);
Dart_Handle prefix = Dart_NewString("");
EXPECT_VALID(imported_lib);
Dart_Handle result = Dart_LibraryImportLibrary(lib, imported_lib, prefix);
EXPECT_VALID(result);
result = Dart_Invoke(imported_lib, Dart_NewString("test2"), 0, NULL);
EXPECT_VALID(result);
// Instance field.
name = Dart_NewString("instance_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(cls, name);
TestFieldOk(instance, name, false, "instance");
// Hidden instance field.
name = Dart_NewString("_instance_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(cls, name);
TestFieldOk(instance, name, false, "hidden instance");
// Final instance field.
name = Dart_NewString("final_instance_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(cls, name);
TestFieldOk(instance, name, true, "final instance");
// Hidden final instance field.
name = Dart_NewString("_final_instance_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(cls, name);
TestFieldOk(instance, name, true, "hidden final instance");
// Inherited field.
name = Dart_NewString("inherited_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(cls, name);
TestFieldOk(instance, name, false, "inherited");
// Instance get/set field.
name = Dart_NewString("instance_getset_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(cls, name);
TestFieldOk(instance, name, false, "instance getset");
// Hidden instance get/set field.
name = Dart_NewString("_instance_getset_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(cls, name);
TestFieldOk(instance, name, false, "hidden instance getset");
// Static field.
name = Dart_NewString("static_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(instance, name);
TestFieldOk(cls, name, false, "static");
// Hidden static field.
name = Dart_NewString("_static_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(instance, name);
TestFieldOk(cls, name, false, "hidden static");
// Static final field.
name = Dart_NewString("const_static_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(instance, name);
TestFieldOk(cls, name, true, "const static");
// Hidden static const field.
name = Dart_NewString("_const_static_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(instance, name);
TestFieldOk(cls, name, true, "hidden const static");
// Static non-inherited field. Not found at any level.
name = Dart_NewString("non_inherited_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(instance, name);
TestFieldNotFound(cls, name);
// Static get/set field.
name = Dart_NewString("static_getset_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(instance, name);
TestFieldOk(cls, name, false, "static getset");
// Hidden static get/set field.
name = Dart_NewString("_static_getset_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(instance, name);
TestFieldOk(cls, name, false, "hidden static getset");
// Top-Level field.
name = Dart_NewString("top_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldOk(lib, name, false, "top");
// Hidden top-level field.
name = Dart_NewString("_top_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldOk(lib, name, false, "hidden top");
// Top-Level final field.
name = Dart_NewString("const_top_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldOk(lib, name, true, "const top");
// Hidden top-level final field.
name = Dart_NewString("_const_top_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldOk(lib, name, true, "hidden const top");
// Top-Level get/set field.
name = Dart_NewString("top_getset_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldOk(lib, name, false, "top getset");
// Hidden top-level get/set field.
name = Dart_NewString("_top_getset_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldOk(lib, name, false, "hidden top getset");
// Imported top-Level field.
name = Dart_NewString("imported_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldOk(lib, name, false, "imported");
// Hidden imported top-level field. Not found at any level.
name = Dart_NewString("_imported_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldNotFound(lib, name);
// Imported top-Level get/set field.
name = Dart_NewString("imported_getset_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldOk(lib, name, false, "imported getset");
// Hidden imported top-level get/set field. Not found at any level.
name = Dart_NewString("_imported_getset_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldNotFound(lib, name);
}
TEST_CASE(SetField_FunnyValue) {
const char* kScriptChars =
"var top;\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle name = Dart_NewString("top");
bool value;
// Test that you can set the field to a good value.
EXPECT_VALID(Dart_SetField(lib, name, Dart_True()));
Dart_Handle result = Dart_GetField(lib, name);
EXPECT_VALID(result);
EXPECT(Dart_IsBoolean(result));
EXPECT_VALID(Dart_BooleanValue(result, &value));
EXPECT(value);
// Test that you can set the field to null
EXPECT_VALID(Dart_SetField(lib, name, Dart_Null()));
result = Dart_GetField(lib, name);
EXPECT_VALID(result);
EXPECT(Dart_IsNull(result));
// Pass a non-instance handle.
result = Dart_SetField(lib, name, lib);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_SetField expects argument 'value' to be of type Instance.",
Dart_GetError(result));
// Pass an error handle. The error is contagious.
result = Dart_SetField(lib, name, Api::NewError("myerror"));
EXPECT(Dart_IsError(result));
EXPECT_STREQ("myerror", Dart_GetError(result));
}
void NativeFieldLookup(Dart_NativeArguments args) {
UNREACHABLE();
}
static Dart_NativeFunction native_field_lookup(Dart_Handle name,
int argument_count) {
return reinterpret_cast<Dart_NativeFunction>(&NativeFieldLookup);
}
TEST_CASE(InjectNativeFields1) {
const char* kScriptChars =
"class NativeFields extends NativeFieldsWrapper {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static const int fld4 = 10;\n"
"}\n"
"NativeFields testMain() {\n"
" NativeFields obj = new NativeFields(10, 20);\n"
" return obj;\n"
"}\n";
Dart_Handle result;
const int kNumNativeFields = 4;
// Create a test library.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars,
native_field_lookup);
// Create a native wrapper class with native fields.
result = Dart_CreateNativeWrapperClass(
lib,
Dart_NewString("NativeFieldsWrapper"),
kNumNativeFields);
// Load up a test script in the test library.
// Invoke a function which returns an object of type NativeFields.
result = Dart_Invoke(lib, Dart_NewString("testMain"), 0, NULL);
EXPECT_VALID(result);
DARTSCOPE_NOCHECKS(Isolate::Current());
Instance& obj = Instance::Handle();
obj ^= Api::UnwrapHandle(result);
const Class& cls = Class::Handle(obj.clazz());
// We expect the newly created "NativeFields" object to have
// 2 dart instance fields (fld1, fld2) and kNumNativeFields native fields.
// Hence the size of an instance of "NativeFields" should be
// (kNumNativeFields + 2) * kWordSize + size of object header.
// We check to make sure the instance size computed by the VM matches
// our expectations.
intptr_t header_size = sizeof(RawObject);
EXPECT_EQ(Utils::RoundUp(((kNumNativeFields + 2) * kWordSize) + header_size,
kObjectAlignment),
cls.instance_size());
}
TEST_CASE(InjectNativeFields2) {
const char* kScriptChars =
"class NativeFields extends NativeFieldsWrapper {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static const int fld4 = 10;\n"
"}\n"
"NativeFields testMain() {\n"
" NativeFields obj = new NativeFields(10, 20);\n"
" return obj;\n"
"}\n";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns an object of type NativeFields.
result = Dart_Invoke(lib, Dart_NewString("testMain"), 0, NULL);
// We expect this to fail as class "NativeFields" extends
// "NativeFieldsWrapper" and there is no definition of it either
// in the dart code or through the native field injection mechanism.
EXPECT(Dart_IsError(result));
}
TEST_CASE(InjectNativeFields3) {
const char* kScriptChars =
"#import('dart:nativewrappers');"
"class NativeFields extends NativeFieldWrapperClass2 {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static const int fld4 = 10;\n"
"}\n"
"NativeFields testMain() {\n"
" NativeFields obj = new NativeFields(10, 20);\n"
" return obj;\n"
"}\n";
Dart_Handle result;
const int kNumNativeFields = 2;
// Load up a test script in the test library.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars,
native_field_lookup);
// Invoke a function which returns an object of type NativeFields.
result = Dart_Invoke(lib, Dart_NewString("testMain"), 0, NULL);
EXPECT_VALID(result);
DARTSCOPE_NOCHECKS(Isolate::Current());
Instance& obj = Instance::Handle();
obj ^= Api::UnwrapHandle(result);
const Class& cls = Class::Handle(obj.clazz());
// We expect the newly created "NativeFields" object to have
// 2 dart instance fields (fld1, fld2) and kNumNativeFields native fields.
// Hence the size of an instance of "NativeFields" should be
// (kNumNativeFields + 2) * kWordSize + size of object header.
// We check to make sure the instance size computed by the VM matches
// our expectations.
intptr_t header_size = sizeof(RawObject);
EXPECT_EQ(Utils::RoundUp(((kNumNativeFields + 2) * kWordSize) + header_size,
kObjectAlignment),
cls.instance_size());
}
TEST_CASE(InjectNativeFields4) {
const char* kScriptChars =
"#import('dart:nativewrappers');"
"class NativeFields extends NativeFieldWrapperClass2 {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static const int fld4 = 10;\n"
"}\n"
"NativeFields testMain() {\n"
" NativeFields obj = new NativeFields(10, 20);\n"
" return obj;\n"
"}\n";
Dart_Handle result;
// Load up a test script in the test library.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns an object of type NativeFields.
result = Dart_Invoke(lib, Dart_NewString("testMain"), 0, NULL);
// We expect the test script to fail finalization with the error below:
EXPECT(Dart_IsError(result));
Dart_Handle expected_error = Dart_Error(
"'dart:test-lib': Error: line 1 pos 38: "
"class 'NativeFields' is trying to extend a native fields class, "
"but library '%s' has no native resolvers",
TestCase::url());
EXPECT_SUBSTRING(Dart_GetError(expected_error), Dart_GetError(result));
}
TEST_CASE(InjectNativeFieldsSuperClass) {
const char* kScriptChars =
"#import('dart:nativewrappers');"
"class NativeFieldsSuper extends NativeFieldWrapperClass1 {\n"
" NativeFieldsSuper() : fld1 = 42 {}\n"
" int fld1;\n"
"}\n"
"class NativeFields extends NativeFieldsSuper {\n"
" fld() => fld1;\n"
"}\n"
"int testMain() {\n"
" NativeFields obj = new NativeFields();\n"
" return obj.fld();\n"
"}\n";
Dart_Handle result;
// Load up a test script in the test library.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, native_field_lookup);
// Invoke a function which returns an object of type NativeFields.
result = Dart_Invoke(lib, Dart_NewString("testMain"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(42, value);
}
static void TestNativeFields(Dart_Handle retobj) {
// Access and set various instance fields of the object.
Dart_Handle result = Dart_GetField(retobj, Dart_NewString("fld3"));
EXPECT(Dart_IsError(result));
result = Dart_GetField(retobj, Dart_NewString("fld0"));
EXPECT_VALID(result);
EXPECT(Dart_IsNull(result));
result = Dart_GetField(retobj, Dart_NewString("fld1"));
EXPECT_VALID(result);
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(10, value);
result = Dart_GetField(retobj, Dart_NewString("fld2"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(20, value);
result = Dart_SetField(retobj,
Dart_NewString("fld2"),
Dart_NewInteger(40));
EXPECT(Dart_IsError(result));
result = Dart_SetField(retobj,
Dart_NewString("fld1"),
Dart_NewInteger(40));
EXPECT_VALID(result);
result = Dart_GetField(retobj, Dart_NewString("fld1"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(40, value);
// Now access and set various native instance fields of the returned object.
const int kNativeFld0 = 0;
const int kNativeFld1 = 1;
const int kNativeFld2 = 2;
const int kNativeFld3 = 3;
const int kNativeFld4 = 4;
int field_count = 0;
intptr_t field_value = 0;
EXPECT_VALID(Dart_GetNativeInstanceFieldCount(retobj, &field_count));
EXPECT_EQ(4, field_count);
result = Dart_GetNativeInstanceField(retobj, kNativeFld4, &field_value);
EXPECT(Dart_IsError(result));
result = Dart_GetNativeInstanceField(retobj, kNativeFld0, &field_value);
EXPECT_VALID(result);
EXPECT_EQ(0, field_value);
result = Dart_GetNativeInstanceField(retobj, kNativeFld1, &field_value);
EXPECT_VALID(result);
EXPECT_EQ(0, field_value);
result = Dart_GetNativeInstanceField(retobj, kNativeFld2, &field_value);
EXPECT_VALID(result);
EXPECT_EQ(0, field_value);
result = Dart_GetNativeInstanceField(retobj, kNativeFld3, &field_value);
EXPECT_VALID(result);
EXPECT_EQ(0, field_value);
result = Dart_SetNativeInstanceField(retobj, kNativeFld4, 40);
EXPECT(Dart_IsError(result));
result = Dart_SetNativeInstanceField(retobj, kNativeFld0, 4);
EXPECT_VALID(result);
result = Dart_SetNativeInstanceField(retobj, kNativeFld1, 40);
EXPECT_VALID(result);
result = Dart_SetNativeInstanceField(retobj, kNativeFld2, 400);
EXPECT_VALID(result);
result = Dart_SetNativeInstanceField(retobj, kNativeFld3, 4000);
EXPECT_VALID(result);
result = Dart_GetNativeInstanceField(retobj, kNativeFld3, &field_value);
EXPECT_VALID(result);
EXPECT_EQ(4000, field_value);
// Now re-access various dart instance fields of the returned object
// to ensure that there was no corruption while setting native fields.
result = Dart_GetField(retobj, Dart_NewString("fld1"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(40, value);
result = Dart_GetField(retobj, Dart_NewString("fld2"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(20, value);
}
TEST_CASE(NativeFieldAccess) {
const char* kScriptChars =
"class NativeFields extends NativeFieldsWrapper {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld0;\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static const int fld4 = 10;\n"
"}\n"
"NativeFields testMain() {\n"
" NativeFields obj = new NativeFields(10, 20);\n"
" return obj;\n"
"}\n";
const int kNumNativeFields = 4;
// Create a test library.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars,
native_field_lookup);
// Create a native wrapper class with native fields.
Dart_Handle result = Dart_CreateNativeWrapperClass(
lib,
Dart_NewString("NativeFieldsWrapper"),
kNumNativeFields);
EXPECT_VALID(result);
// Load up a test script in it.
// Invoke a function which returns an object of type NativeFields.
Dart_Handle retobj = Dart_Invoke(lib, Dart_NewString("testMain"), 0, NULL);
EXPECT_VALID(retobj);
// Now access and set various instance fields of the returned object.
TestNativeFields(retobj);
// Test that accessing an error handle propagates the error.
Dart_Handle error = Api::NewError("myerror");
intptr_t field_value = 0;
result = Dart_GetNativeInstanceField(error, 0, &field_value);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("myerror", Dart_GetError(result));
result = Dart_SetNativeInstanceField(error, 0, 1);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("myerror", Dart_GetError(result));
}
TEST_CASE(ImplicitNativeFieldAccess) {
const char* kScriptChars =
"#import('dart:nativewrappers');"
"class NativeFields extends NativeFieldWrapperClass4 {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld0;\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static const int fld4 = 10;\n"
"}\n"
"NativeFields testMain() {\n"
" NativeFields obj = new NativeFields(10, 20);\n"
" return obj;\n"
"}\n";
// Load up a test script in the test library.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars,
native_field_lookup);
// Invoke a function which returns an object of type NativeFields.
Dart_Handle retobj = Dart_Invoke(lib, Dart_NewString("testMain"), 0, NULL);
EXPECT_VALID(retobj);
// Now access and set various instance fields of the returned object.
TestNativeFields(retobj);
}
TEST_CASE(NegativeNativeFieldAccess) {
const char* kScriptChars =
"class NativeFields {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static const int fld4 = 10;\n"
"}\n"
"NativeFields testMain1() {\n"
" NativeFields obj = new NativeFields(10, 20);\n"
" return obj;\n"
"}\n"
"Function testMain2() {\n"
" return function() {};\n"
"}\n";
Dart_Handle result;
DARTSCOPE_NOCHECKS(Isolate::Current());
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns an object of type NativeFields.
Dart_Handle retobj = Dart_Invoke(lib, Dart_NewString("testMain1"), 0, NULL);
EXPECT_VALID(retobj);
// Now access and set various native instance fields of the returned object.
// All of these tests are expected to return failure as there are no
// native fields in an instance of NativeFields.
const int kNativeFld0 = 0;
const int kNativeFld1 = 1;
const int kNativeFld2 = 2;
const int kNativeFld3 = 3;
const int kNativeFld4 = 4;
intptr_t value = 0;
result = Dart_GetNativeInstanceField(retobj, kNativeFld4, &value);
EXPECT(Dart_IsError(result));
result = Dart_GetNativeInstanceField(retobj, kNativeFld0, &value);
EXPECT(Dart_IsError(result));
result = Dart_GetNativeInstanceField(retobj, kNativeFld1, &value);
EXPECT(Dart_IsError(result));
result = Dart_GetNativeInstanceField(retobj, kNativeFld2, &value);
EXPECT(Dart_IsError(result));
result = Dart_SetNativeInstanceField(retobj, kNativeFld4, 40);
EXPECT(Dart_IsError(result));
result = Dart_SetNativeInstanceField(retobj, kNativeFld3, 40);
EXPECT(Dart_IsError(result));
result = Dart_SetNativeInstanceField(retobj, kNativeFld0, 400);
EXPECT(Dart_IsError(result));
// Invoke a function which returns a closure object.
retobj = Dart_Invoke(lib, Dart_NewString("testMain2"), 0, NULL);
EXPECT_VALID(retobj);
result = Dart_GetNativeInstanceField(retobj, kNativeFld4, &value);
EXPECT(Dart_IsError(result));
result = Dart_GetNativeInstanceField(retobj, kNativeFld0, &value);
EXPECT(Dart_IsError(result));
result = Dart_GetNativeInstanceField(retobj, kNativeFld1, &value);
EXPECT(Dart_IsError(result));
result = Dart_GetNativeInstanceField(retobj, kNativeFld2, &value);
EXPECT(Dart_IsError(result));
result = Dart_SetNativeInstanceField(retobj, kNativeFld4, 40);
EXPECT(Dart_IsError(result));
result = Dart_SetNativeInstanceField(retobj, kNativeFld3, 40);
EXPECT(Dart_IsError(result));
result = Dart_SetNativeInstanceField(retobj, kNativeFld0, 400);
EXPECT(Dart_IsError(result));
}
TEST_CASE(GetStaticField_RunsInitializer) {
const char* kScriptChars =
"class TestClass {\n"
" static const int fld1 = 7;\n"
" static int fld2 = 11;\n"
" static void testMain() {\n"
" }\n"
"}\n";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("TestClass"));
EXPECT_VALID(cls);
// Invoke a function which returns an object.
result = Dart_Invoke(cls, Dart_NewString("testMain"), 0, NULL);
EXPECT_VALID(result);
// For uninitialized fields, the getter is returned
result = Dart_GetField(cls, Dart_NewString("fld1"));
EXPECT_VALID(result);
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(7, value);
result = Dart_GetField(cls, Dart_NewString("fld2"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(11, value);
// Overwrite fld2
result = Dart_SetField(cls,
Dart_NewString("fld2"),
Dart_NewInteger(13));
EXPECT_VALID(result);
// We now get the new value for fld2, not the initializer
result = Dart_GetField(cls, Dart_NewString("fld2"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(13, value);
}
TEST_CASE(New) {
const char* kScriptChars =
"class MyClass implements MyInterface {\n"
" MyClass() : foo = 7 {}\n"
" MyClass.named(value) : foo = value {}\n"
" MyClass._hidden(value) : foo = -value {}\n"
" MyClass.exception(value) : foo = value {\n"
" throw 'ConstructorDeath';\n"
" }\n"
" factory MyClass.multiply(value) {\n"
" return new MyClass.named(value * 100);\n"
" }\n"
" factory MyClass.nullo() {\n"
" return null;\n"
" }\n"
" factory MyInterface.multiply(value) { // won't get called.\n"
" return new MyClass.named(value * 1000);\n"
" }\n"
" factory MyInterface2.unused(value) {\n"
" return new MyClass2(-value);\n"
" }\n"
" factory MyInterface2.multiply(value) {\n"
" return new MyClass2(value * 10000);\n"
" }\n"
" var foo;\n"
"}\n"
"\n"
"class MyClass2 implements MyInterface2 {\n"
" MyClass2(value) : bar = value {}\n"
" var bar;\n"
"}\n"
"\n"
"interface MyInterface default MyClass {\n"
" MyInterface.named(value);\n"
" MyInterface.multiply(value);\n"
" MyInterface.notfound(value);\n"
"}\n"
"\n"
"interface MyInterface2 default MyClass {\n"
" MyInterface2.multiply(value);\n"
" MyInterface2.notfound(value);\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("MyClass"));
EXPECT_VALID(cls);
Dart_Handle cls2 = Dart_GetClass(lib, Dart_NewString("MyClass2"));
EXPECT_VALID(cls2);
Dart_Handle intf = Dart_GetClass(lib, Dart_NewString("MyInterface"));
EXPECT_VALID(intf);
Dart_Handle intf2 = Dart_GetClass(lib, Dart_NewString("MyInterface2"));
EXPECT_VALID(intf2);
Dart_Handle args[1];
args[0] = Dart_NewInteger(11);
Dart_Handle bad_args[1];
bad_args[0] = Dart_Error("myerror");
// Invoke the unnamed constructor.
Dart_Handle result = Dart_New(cls, Dart_Null(), 0, NULL);
EXPECT_VALID(result);
bool instanceof = false;
EXPECT_VALID(Dart_ObjectIsType(result, cls, &instanceof));
EXPECT(instanceof);
int64_t int_value = 0;
Dart_Handle foo = Dart_GetField(result, Dart_NewString("foo"));
EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
EXPECT_EQ(7, int_value);
// Invoke the unnamed constructor with an empty string.
result = Dart_New(cls, Dart_NewString(""), 0, NULL);
EXPECT_VALID(result);
instanceof = false;
EXPECT_VALID(Dart_ObjectIsType(result, cls, &instanceof));
EXPECT(instanceof);
int_value = 0;
foo = Dart_GetField(result, Dart_NewString("foo"));
EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
EXPECT_EQ(7, int_value);
// Invoke a named constructor.
result = Dart_New(cls, Dart_NewString("named"), 1, args);
EXPECT_VALID(result);
EXPECT_VALID(Dart_ObjectIsType(result, cls, &instanceof));
EXPECT(instanceof);
int_value = 0;
foo = Dart_GetField(result, Dart_NewString("foo"));
EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
EXPECT_EQ(11, int_value);
// Invoke a hidden named constructor.
result = Dart_New(cls, Dart_NewString("_hidden"), 1, args);
EXPECT_VALID(result);
EXPECT_VALID(Dart_ObjectIsType(result, cls, &instanceof));
EXPECT(instanceof);
int_value = 0;
foo = Dart_GetField(result, Dart_NewString("foo"));
EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
EXPECT_EQ(-11, int_value);
// Invoke a factory constructor.
result = Dart_New(cls, Dart_NewString("multiply"), 1, args);
EXPECT_VALID(result);
EXPECT_VALID(Dart_ObjectIsType(result, cls, &instanceof));
EXPECT(instanceof);
int_value = 0;
foo = Dart_GetField(result, Dart_NewString("foo"));
EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
EXPECT_EQ(1100, int_value);
// Invoke a factory constructor which returns null.
result = Dart_New(cls, Dart_NewString("nullo"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsNull(result));
// Pass an error class object. Error is passed through.
result = Dart_New(Dart_Error("myerror"), Dart_NewString("named"), 1, args);
EXPECT_ERROR(result, "myerror");
// Pass a bad class object.
result = Dart_New(Dart_Null(), Dart_NewString("named"), 1, args);
EXPECT_ERROR(result, "Dart_New expects argument 'clazz' to be non-null.");
// Pass a negative arg count.
result = Dart_New(cls, Dart_NewString("named"), -1, args);
EXPECT_ERROR(
result,
"Dart_New expects argument 'number_of_arguments' to be non-negative.");
// Pass the wrong arg count.
result = Dart_New(cls, Dart_NewString("named"), 0, NULL);
EXPECT_ERROR(
result,
"Dart_New: wrong argument count for constructor 'MyClass.named': "
"0 passed, 1 expected.");
// Pass a bad argument. Error is passed through.
result = Dart_New(cls, Dart_NewString("named"), 1, bad_args);
EXPECT_ERROR(result, "myerror");
// Pass a bad constructor name.
result = Dart_New(cls, Dart_NewInteger(55), 1, args);
EXPECT_ERROR(
result,
"Dart_New expects argument 'constructor_name' to be of type String.");
// Invoke a missing constructor.
result = Dart_New(cls, Dart_NewString("missing"), 1, args);
EXPECT_ERROR(result,
"Dart_New: could not find constructor 'MyClass.missing'.");
// Invoke a constructor which throws an exception.
result = Dart_New(cls, Dart_NewString("exception"), 1, args);
EXPECT_ERROR(result, "ConstructorDeath");
// MyInterface has default class MyClass.
//
// MyClass *implements* MyInterface.
//
// Therefore the constructor call:
//
// MyInterface.foo()
//
// Becomes:
//
// MyClass.foo() from the class MyClass.
// Invoke an interface constructor.
result = Dart_New(intf, Dart_NewString("named"), 1, args);
EXPECT_VALID(result);
EXPECT_VALID(Dart_ObjectIsType(result, cls, &instanceof));
EXPECT(instanceof);
int_value = 0;
foo = Dart_GetField(result, Dart_NewString("foo"));
EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
EXPECT_EQ(11, int_value);
// Invoke an interface constructor which in turn calls a factory
// constructor.
result = Dart_New(intf, Dart_NewString("multiply"), 1, args);
EXPECT_VALID(result);
EXPECT_VALID(Dart_ObjectIsType(result, cls, &instanceof));
EXPECT(instanceof);
int_value = 0;
foo = Dart_GetField(result, Dart_NewString("foo"));
EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
EXPECT_EQ(1100, int_value);
// Invoke a constructor that is missing in the interface but present
// in the default class.
result = Dart_New(intf, Dart_Null(), 0, NULL);
EXPECT_ERROR(result,
"Dart_New: could not find constructor 'MyInterface.'.");
// Invoke a constructor that is present in the interface but missing
// in the default class.
result = Dart_New(intf, Dart_NewString("notfound"), 1, args);
EXPECT_ERROR(result,
"Dart_New: could not find constructor 'MyClass.notfound'.");
// MyInterface2 has default class MyClass.
//
// MyClass *does not implement* MyInterface2.
//
// Therefore the constructor call:
//
// new MyInterface2.foo()
//
// Becomes:
//
// new MyInterface2.foo() from the class MyClass.
// Invoke an interface constructor which in turn calls a factory
// constructor.
result = Dart_New(intf2, Dart_NewString("multiply"), 1, args);
EXPECT_VALID(result);
EXPECT_VALID(Dart_ObjectIsType(result, cls2, &instanceof));
EXPECT(instanceof);
int_value = 0;
Dart_Handle bar = Dart_GetField(result, Dart_NewString("bar"));
EXPECT_VALID(Dart_IntegerToInt64(bar, &int_value));
EXPECT_EQ(110000, int_value);
// Invoke a constructor that is missing in the interface but present
// in the default class.
result = Dart_New(intf2, Dart_NewString("unused"), 1, args);
EXPECT_ERROR(result,
"Dart_New: could not find constructor 'MyInterface2.unused'.");
// Invoke a constructor that is present in the interface but missing
// in the default class.
result = Dart_New(intf2, Dart_NewString("notfound"), 1, args);
EXPECT_ERROR(result,
"Dart_New: could not find factory 'MyInterface2.notfound' "
"in class 'MyClass'.");
}
TEST_CASE(New_Issue2971) {
// Issue 2971: We were unable to use Dart_New to construct an
// instance of List, due to problems implementing interface
// factories.
Dart_Handle core_lib = Dart_LookupLibrary(Dart_NewString("dart:core"));
EXPECT_VALID(core_lib);
Dart_Handle list_class = Dart_GetClass(core_lib, Dart_NewString("List"));
EXPECT_VALID(list_class);
const int kNumArgs = 1;
Dart_Handle args[kNumArgs];
args[0] = Dart_NewInteger(1);
Dart_Handle list_obj = Dart_New(list_class, Dart_Null(), kNumArgs, args);
EXPECT_VALID(list_obj);
EXPECT(Dart_IsList(list_obj));
}
TEST_CASE(Invoke) {
const char* kScriptChars =
"class BaseMethods {\n"
" inheritedMethod(arg) => 'inherited $arg';\n"
" static nonInheritedMethod(arg) => 'noninherited $arg';\n"
"}\n"
"\n"
"class Methods extends BaseMethods {\n"
" instanceMethod(arg) => 'instance $arg';\n"
" _instanceMethod(arg) => 'hidden instance $arg';\n"
" static staticMethod(arg) => 'static $arg';\n"
" static _staticMethod(arg) => 'hidden static $arg';\n"
"}\n"
"\n"
"topMethod(arg) => 'top $arg';\n"
"_topMethod(arg) => 'hidden top $arg';\n"
"\n"
"Methods test() {\n"
" return new Methods();\n"
"}\n";
// Shared setup.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("Methods"));
EXPECT_VALID(cls);
Dart_Handle instance = Dart_Invoke(lib, Dart_NewString("test"), 0, NULL);
EXPECT_VALID(instance);
Dart_Handle args[1];
args[0] = Dart_NewString("!!!");
Dart_Handle bad_args[2];
bad_args[0] = Dart_NewString("bad1");
bad_args[1] = Dart_NewString("bad2");
Dart_Handle result;
Dart_Handle name;
const char* str;
// Instance method.
name = Dart_NewString("instanceMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
result = Dart_Invoke(instance, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("instance !!!", str);
// Instance method, wrong arg count.
EXPECT_ERROR(Dart_Invoke(instance, name, 2, bad_args),
"did not find instance method 'Methods.instanceMethod'");
// Hidden instance method.
name = Dart_NewString("_instanceMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
result = Dart_Invoke(instance, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hidden instance !!!", str);
// Inherited method.
name = Dart_NewString("inheritedMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
result = Dart_Invoke(instance, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("inherited !!!", str);
// Static method.
name = Dart_NewString("staticMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
result = Dart_Invoke(cls, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("static !!!", str);
// Static method, wrong arg count.
EXPECT_ERROR(Dart_Invoke(cls, name, 2, bad_args),
"did not find static method 'Methods.staticMethod'");
// Hidden static method.
name = Dart_NewString("_staticMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
result = Dart_Invoke(cls, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hidden static !!!", str);
// Static non-inherited method. Not found at any level.
name = Dart_NewString("non_inheritedMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
// Top-Level method.
name = Dart_NewString("topMethod");
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
result = Dart_Invoke(lib, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("top !!!", str);
// Top-level method, wrong arg count.
EXPECT_ERROR(Dart_Invoke(lib, name, 2, bad_args),
"Dart_Invoke: wrong argument count for function 'topMethod': "
"2 passed, 1 expected.");
// Hidden top-level method.
name = Dart_NewString("_topMethod");
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
result = Dart_Invoke(lib, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hidden top !!!", str);
}
TEST_CASE(Invoke_FunnyArgs) {
const char* kScriptChars =
"test(arg) => 'hello $arg';\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle func_name = Dart_NewString("test");
Dart_Handle args[1];
const char* str;
// Make sure that valid args yield valid results.
args[0] = Dart_NewString("!!!");
Dart_Handle result = Dart_Invoke(lib, func_name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hello !!!", str);
// Make sure that null is legal.
args[0] = Dart_Null();
result = Dart_Invoke(lib, func_name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hello null", str);
// Pass an error handle as the target. The error is propagated.
result = Dart_Invoke(Api::NewError("myerror"),
func_name, 1, args);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("myerror", Dart_GetError(result));
// Pass an error handle as the function name. The error is propagated.
result = Dart_Invoke(lib, Api::NewError("myerror"), 1, args);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("myerror", Dart_GetError(result));
// Pass a non-instance handle as a parameter..
args[0] = lib;
result = Dart_Invoke(lib, func_name, 1, args);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_Invoke expects arguments[0] to be an Instance handle.",
Dart_GetError(result));
// Pass an error handle as a parameter. The error is propagated.
args[0] = Api::NewError("myerror");
result = Dart_Invoke(lib, func_name, 1, args);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("myerror", Dart_GetError(result));
}
TEST_CASE(Invoke_Null) {
Dart_Handle result = Dart_Invoke(Dart_Null(),
Dart_NewString("toString"),
0,
NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsString(result));
const char* value = "";
EXPECT_VALID(Dart_StringToCString(result, &value));
EXPECT_STREQ("null", value);
// Should throw a NullPointerException. Disabled due to bug 5415268.
/*
Dart_Handle function_name2 = Dart_NewString("NoNoNo");
result = Dart_Invoke(null_receiver,
function_name2,
number_of_arguments,
dart_arguments);
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result)); */
}
TEST_CASE(Invoke_CrossLibrary) {
const char* kLibrary1Chars =
"#library('library1_name');\n"
"void local() {}\n"
"void _local() {}\n";
const char* kLibrary2Chars =
"#library('library2_name');\n"
"void imported() {}\n"
"void _imported() {}\n";
// Load lib1
Dart_Handle url = Dart_NewString("library1_url");
Dart_Handle source = Dart_NewString(kLibrary1Chars);
Dart_Handle lib1 = Dart_LoadLibrary(url, source);
EXPECT_VALID(lib1);
// Load lib2
url = Dart_NewString("library2_url");
source = Dart_NewString(kLibrary2Chars);
Dart_Handle lib2 = Dart_LoadLibrary(url, source);
EXPECT_VALID(lib2);
// Import lib2 from lib1
Dart_Handle result = Dart_LibraryImportLibrary(lib1, lib2, Dart_Null());
EXPECT_VALID(result);
// We can invoke both private and non-private local functions.
EXPECT_VALID(Dart_Invoke(lib1, Dart_NewString("local"), 0, NULL));
EXPECT_VALID(Dart_Invoke(lib1, Dart_NewString("_local"), 0, NULL));
// We can only invoke non-private imported functions.
EXPECT_VALID(Dart_Invoke(lib1, Dart_NewString("imported"), 0, NULL));
EXPECT_ERROR(Dart_Invoke(lib1, Dart_NewString("_imported"), 0, NULL),
"did not find top-level function '_imported'");
}
TEST_CASE(ClosureFunction) {
const char* kScriptChars =
"Function getClosure() {\n"
" return (x, y, [z]) => x + y + z;\n"
"}\n"
"class Foo {\n"
" getInstanceClosure() {\n"
" return () { return this; };\n"
" }\n"
" getInstanceClosureWithArgs() {\n"
" return (x, y, [z]) { return this; };\n"
" }\n"
" static getStaticClosure() {\n"
" return () { return 42; };\n"
" }\n"
" static getStaticClosureWithArgs() {\n"
" return (x, y, [z]) { return 42; };\n"
" }\n"
"}\n"
"Function getInstanceClosure() {\n"
" return new Foo().getInstanceClosure();\n"
"}\n"
"Function getInstanceClosureWithArgs() {\n"
" return new Foo().getInstanceClosureWithArgs();\n"
"}\n"
"Function getStaticClosure() {\n"
" return Foo.getStaticClosure();\n"
"}\n"
"Function getStaticClosureWithArgs() {\n"
" return Foo.getStaticClosureWithArgs();\n"
"}\n";
Dart_Handle result;
Dart_Handle owner;
Dart_Handle defining_function;
DARTSCOPE_NOCHECKS(Isolate::Current());
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(lib);
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("Foo"));
EXPECT_VALID(cls);
// Invoke a function which returns a closure.
Dart_Handle retobj = Dart_Invoke(lib, Dart_NewString("getClosure"), 0, NULL);
EXPECT_VALID(retobj);
EXPECT(Dart_IsClosure(retobj));
EXPECT(!Dart_IsClosure(Dart_NewInteger(101)));
// Retrieve the closure's function
result = Dart_ClosureFunction(retobj);
EXPECT_VALID(result);
EXPECT(Dart_IsFunction(result));
owner = Dart_FunctionOwner(result);
EXPECT_VALID(owner);
defining_function = Dart_LookupFunction(lib, Dart_NewString("getClosure"));
EXPECT(Dart_IdentityEquals(owner, defining_function));
int64_t fixed_param_count = -999;
int64_t opt_param_count = -999;
result = Dart_FunctionParameterCounts(result,
&fixed_param_count,
&opt_param_count);
EXPECT_VALID(result);
EXPECT_EQ(2, fixed_param_count);
EXPECT_EQ(1, opt_param_count);
// Try to retrieve function from a non-closure object
result = Dart_ClosureFunction(Dart_NewInteger(1));
EXPECT(Dart_IsError(result));
// Invoke a function which returns an "instance" closure.
retobj = Dart_Invoke(lib, Dart_NewString("getInstanceClosure"), 0, NULL);
EXPECT_VALID(retobj);
EXPECT(Dart_IsClosure(retobj));
// Retrieve the closure's function
result = Dart_ClosureFunction(retobj);
EXPECT_VALID(result);
EXPECT(Dart_IsFunction(result));
owner = Dart_FunctionOwner(result);
EXPECT_VALID(owner);
defining_function = Dart_LookupFunction(cls,
Dart_NewString("getInstanceClosure"));
EXPECT(Dart_IdentityEquals(owner, defining_function));
// -999: We want to distinguish between a non-answer and a wrong answer, and
// -1 has been a previous wrong answer
fixed_param_count = -999;
opt_param_count = -999;
result = Dart_FunctionParameterCounts(result,
&fixed_param_count,
&opt_param_count);
EXPECT_VALID(result);
EXPECT_EQ(0, fixed_param_count);
EXPECT_EQ(0, opt_param_count);
// Invoke a function which returns an "instance" closure with arguments.
retobj = Dart_Invoke(lib,
Dart_NewString("getInstanceClosureWithArgs"),
0,
NULL);
EXPECT_VALID(retobj);
EXPECT(Dart_IsClosure(retobj));
// Retrieve the closure's function
result = Dart_ClosureFunction(retobj);
EXPECT_VALID(result);
EXPECT(Dart_IsFunction(result));
owner = Dart_FunctionOwner(result);
EXPECT_VALID(owner);
defining_function =
Dart_LookupFunction(cls, Dart_NewString("getInstanceClosureWithArgs"));
EXPECT(Dart_IdentityEquals(owner, defining_function));
// -999: We want to distinguish between a non-answer and a wrong answer, and
// -1 has been a previous wrong answer
fixed_param_count = -999;
opt_param_count = -999;
result = Dart_FunctionParameterCounts(result,
&fixed_param_count,
&opt_param_count);
EXPECT_VALID(result);
EXPECT_EQ(2, fixed_param_count);
EXPECT_EQ(1, opt_param_count);
// Invoke a function which returns a "static" closure.
retobj = Dart_Invoke(lib, Dart_NewString("getStaticClosure"), 0, NULL);
EXPECT_VALID(retobj);
EXPECT(Dart_IsClosure(retobj));
// Retrieve the closure's function
result = Dart_ClosureFunction(retobj);
EXPECT_VALID(result);
EXPECT(Dart_IsFunction(result));
owner = Dart_FunctionOwner(result);
EXPECT_VALID(owner);
defining_function = Dart_LookupFunction(cls,
Dart_NewString("getStaticClosure"));
EXPECT(Dart_IdentityEquals(owner, defining_function));
// -999: We want to distinguish between a non-answer and a wrong answer, and
// -1 has been a previous wrong answer
fixed_param_count = -999;
opt_param_count = -999;
result = Dart_FunctionParameterCounts(result,
&fixed_param_count,
&opt_param_count);
EXPECT_VALID(result);
EXPECT_EQ(0, fixed_param_count);
EXPECT_EQ(0, opt_param_count);
// Invoke a function which returns a "static" closure with arguments.
retobj = Dart_Invoke(lib,
Dart_NewString("getStaticClosureWithArgs"),
0,
NULL);
EXPECT_VALID(retobj);
EXPECT(Dart_IsClosure(retobj));
// Retrieve the closure's function
result = Dart_ClosureFunction(retobj);
EXPECT_VALID(result);
EXPECT(Dart_IsFunction(result));
owner = Dart_FunctionOwner(result);
EXPECT_VALID(owner);
defining_function =
Dart_LookupFunction(cls, Dart_NewString("getStaticClosureWithArgs"));
EXPECT(Dart_IdentityEquals(owner, defining_function));
// -999: We want to distinguish between a non-answer and a wrong answer, and
// -1 has been a previous wrong answer
fixed_param_count = -999;
opt_param_count = -999;
result = Dart_FunctionParameterCounts(result,
&fixed_param_count,
&opt_param_count);
EXPECT_VALID(result);
EXPECT_EQ(2, fixed_param_count);
EXPECT_EQ(1, opt_param_count);
}
TEST_CASE(InvokeClosure) {
const char* kScriptChars =
"class InvokeClosure {\n"
" InvokeClosure(int i, int j) : fld1 = i, fld2 = j {}\n"
" Function method1(int i) {\n"
" f(int j) => j + i + fld1 + fld2 + fld4; \n"
" return f;\n"
" }\n"
" static Function method2(int i) {\n"
" n(int j) => true + i + fld4; \n"
" return n;\n"
" }\n"
" int fld1;\n"
" final int fld2;\n"
" static const int fld4 = 10;\n"
"}\n"
"Function testMain1() {\n"
" InvokeClosure obj = new InvokeClosure(10, 20);\n"
" return obj.method1(10);\n"
"}\n"
"Function testMain2() {\n"
" return InvokeClosure.method2(10);\n"
"}\n";
Dart_Handle result;
DARTSCOPE_NOCHECKS(Isolate::Current());
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns a closure.
Dart_Handle retobj = Dart_Invoke(lib, Dart_NewString("testMain1"), 0, NULL);
EXPECT_VALID(retobj);
EXPECT(Dart_IsClosure(retobj));
EXPECT(!Dart_IsClosure(Dart_NewInteger(101)));
// Now invoke the closure and check the result.
Dart_Handle dart_arguments[1];
dart_arguments[0] = Dart_NewInteger(1);
result = Dart_InvokeClosure(retobj, 1, dart_arguments);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(51, value);
// Invoke closure with wrong number of args, should result in exception.
result = Dart_InvokeClosure(retobj, 0, NULL);
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result));
// Invoke a function which returns a closure.
retobj = Dart_Invoke(lib, Dart_NewString("testMain2"), 0, NULL);
EXPECT_VALID(retobj);
EXPECT(Dart_IsClosure(retobj));
EXPECT(!Dart_IsClosure(Dart_NewString("abcdef")));
// Now invoke the closure and check the result (should be an exception).
dart_arguments[0] = Dart_NewInteger(1);
result = Dart_InvokeClosure(retobj, 1, dart_arguments);
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result));
}
void ExceptionNative(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_ThrowException(Dart_NewString("Hello from ExceptionNative!"));
UNREACHABLE();
}
static Dart_NativeFunction native_lookup(Dart_Handle name, int argument_count) {
return reinterpret_cast<Dart_NativeFunction>(&ExceptionNative);
}
TEST_CASE(ThrowException) {
const char* kScriptChars =
"int test() native \"ThrowException_native\";";
Dart_Handle result;
Isolate* isolate = Isolate::Current();
EXPECT(isolate != NULL);
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
intptr_t size = state->ZoneSizeInBytes();
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
// Load up a test script which extends the native wrapper class.
Dart_Handle lib = TestCase::LoadTestScript(
kScriptChars,
reinterpret_cast<Dart_NativeEntryResolver>(native_lookup));
// Throwing an exception here should result in an error.
result = Dart_ThrowException(Dart_NewString("This doesn't work"));
EXPECT_ERROR(result, "No Dart frames on stack, cannot throw exception");
EXPECT(!Dart_ErrorHasException(result));
// Invoke 'test' and check for an uncaught exception.
result = Dart_Invoke(lib, Dart_NewString("test"), 0, NULL);
EXPECT_ERROR(result, "Hello from ExceptionNative!");
EXPECT(Dart_ErrorHasException(result));
Dart_ExitScope(); // Exit the Dart API scope.
EXPECT_EQ(size, state->ZoneSizeInBytes());
}
void NativeArgumentCounter(Dart_NativeArguments args) {
Dart_EnterScope();
int count = Dart_GetNativeArgumentCount(args);
Dart_SetReturnValue(args, Dart_NewInteger(count));
Dart_ExitScope();
}
static Dart_NativeFunction gnac_lookup(Dart_Handle name, int argument_count) {
return reinterpret_cast<Dart_NativeFunction>(&NativeArgumentCounter);
}
TEST_CASE(GetNativeArgumentCount) {
const char* kScriptChars =
"class MyObject {"
" int method1(int i, int j) native 'Name_Does_Not_Matter';"
"}"
"testMain() {"
" MyObject obj = new MyObject();"
" return obj.method1(77, 125);"
"}";
Dart_Handle lib = TestCase::LoadTestScript(
kScriptChars,
reinterpret_cast<Dart_NativeEntryResolver>(gnac_lookup));
Dart_Handle result = Dart_Invoke(lib, Dart_NewString("testMain"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(3, value);
}
TEST_CASE(GetClass) {
const char* kScriptChars =
"class Class {\n"
" static var name = 'Class';\n"
"}\n"
"\n"
"class _Class {\n"
" static var name = '_Class';\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Lookup a class.
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("Class"));
EXPECT_VALID(cls);
Dart_Handle name = Dart_GetField(cls, Dart_NewString("name"));
EXPECT_VALID(name);
const char* name_cstr = "";
EXPECT_VALID(Dart_StringToCString(name, &name_cstr));
EXPECT_STREQ("Class", name_cstr);
// Lookup a private class.
cls = Dart_GetClass(lib, Dart_NewString("_Class"));
EXPECT_VALID(cls);
name = Dart_GetField(cls, Dart_NewString("name"));
EXPECT_VALID(name);
name_cstr = "";
EXPECT_VALID(Dart_StringToCString(name, &name_cstr));
EXPECT_STREQ("_Class", name_cstr);
// Lookup a class that does not exist.
cls = Dart_GetClass(lib, Dart_NewString("DoesNotExist"));
EXPECT(Dart_IsError(cls));
EXPECT_STREQ("Class 'DoesNotExist' not found in library 'dart:test-lib'.",
Dart_GetError(cls));
// Lookup a class from an error library. The error propagates.
cls = Dart_GetClass(Api::NewError("myerror"), Dart_NewString("Class"));
EXPECT(Dart_IsError(cls));
EXPECT_STREQ("myerror", Dart_GetError(cls));
// Lookup a class using an error class name. The error propagates.
cls = Dart_GetClass(lib, Api::NewError("myerror"));
EXPECT(Dart_IsError(cls));
EXPECT_STREQ("myerror", Dart_GetError(cls));
}
static void BuildFunctionDescription(TextBuffer* buffer, Dart_Handle func) {
buffer->Clear();
if (Dart_IsNull(func)) {
WARN("Function not found");
return;
}
Dart_Handle name = Dart_FunctionName(func);
EXPECT_VALID(name);
const char* name_cstr = "";
EXPECT_VALID(Dart_StringToCString(name, &name_cstr));
bool is_abstract = false;
bool is_static = false;
bool is_getter = false;
bool is_setter = false;
bool is_constructor = false;
int64_t fixed_param_count = -1;
int64_t opt_param_count = -1;
EXPECT_VALID(Dart_FunctionIsAbstract(func, &is_abstract));
EXPECT_VALID(Dart_FunctionIsStatic(func, &is_static));
EXPECT_VALID(Dart_FunctionIsGetter(func, &is_getter));
EXPECT_VALID(Dart_FunctionIsSetter(func, &is_setter));
EXPECT_VALID(Dart_FunctionIsConstructor(func, &is_constructor));
EXPECT_VALID(Dart_FunctionParameterCounts(func,
&fixed_param_count, &opt_param_count));
buffer->Printf("%s %"Pd64" %"Pd64"",
name_cstr,
fixed_param_count,
opt_param_count);
if (is_abstract) {
buffer->Printf(" abstract");
}
if (is_static) {
buffer->Printf(" static");
}
if (is_getter) {
buffer->Printf(" getter");
}
if (is_setter) {
buffer->Printf(" setter");
}
if (is_constructor) {
buffer->Printf(" constructor");
}
}
TEST_CASE(FunctionReflection) {
const char* kScriptChars =
"a() => 'a';\n"
"_b() => '_b';\n"
"get c => 'bar';\n"
"set d(x) {}\n"
"get _e => 'bar';\n"
"set _f(x) {}\n"
"class MyClass {\n"
" MyClass() {}\n"
" MyClass.named() {}\n"
" a() => 'a';\n"
" _b() => '_b';\n"
" get c => 'bar';\n"
" set d(x) {}\n"
" get _e => 'bar';\n"
" set _f(x) {}\n"
" static g() => 'g';\n"
" static _h() => '_h';\n"
" static get i => 'i';\n"
" static set j(x) {}\n"
" static get _k => 'k';\n"
" static set _l(x) {}\n"
" abstract m();\n"
" abstract _n();\n"
" abstract get o;\n"
" abstract set p(x);\n"
" abstract get _q;\n"
" abstract set _r(x);\n"
" s(x, [y, z]) {}\n"
" t([x, y, z]) {}\n"
" operator ==(x) {}\n"
"}\n"
"class _PrivateClass {\n"
" _PrivateClass() {}\n"
" _PrivateClass.named() {}\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(lib);
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("MyClass"));
EXPECT_VALID(cls);
Dart_Handle private_cls = Dart_GetClass(lib, Dart_NewString("_PrivateClass"));
EXPECT_VALID(private_cls);
TextBuffer buffer(128);
// Lookup a top-level function.
Dart_Handle func = Dart_LookupFunction(lib, Dart_NewString("a"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("a 0 0 static", buffer.buf());
EXPECT(Dart_IsLibrary(Dart_FunctionOwner(func)));
Dart_Handle owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, lib));
// Lookup a private top-level function.
func = Dart_LookupFunction(lib, Dart_NewString("_b"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("_b 0 0 static", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, lib));
// Lookup a top-level getter.
func = Dart_LookupFunction(lib, Dart_NewString("c"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("c 0 0 static getter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, lib));
// Lookup a top-level setter.
func = Dart_LookupFunction(lib, Dart_NewString("d="));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("d= 1 0 static setter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, lib));
// Lookup a private top-level getter.
func = Dart_LookupFunction(lib, Dart_NewString("_e"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("_e 0 0 static getter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, lib));
// Lookup a private top-level setter.
func = Dart_LookupFunction(lib, Dart_NewString("_f="));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("_f= 1 0 static setter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, lib));
// Lookup an unnamed constructor
func = Dart_LookupFunction(cls, Dart_NewString("MyClass"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("MyClass 0 0 constructor", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a named constructor
func = Dart_LookupFunction(cls, Dart_NewString("MyClass.named"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("MyClass.named 0 0 constructor", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup an private unnamed constructor
func = Dart_LookupFunction(private_cls, Dart_NewString("_PrivateClass"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("_PrivateClass 0 0 constructor", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, private_cls));
// Lookup a private named constructor
func = Dart_LookupFunction(private_cls,
Dart_NewString("_PrivateClass.named"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("_PrivateClass.named 0 0 constructor", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, private_cls));
// Lookup a method.
func = Dart_LookupFunction(cls, Dart_NewString("a"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("a 0 0", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a private method.
func = Dart_LookupFunction(cls, Dart_NewString("_b"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("_b 0 0", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a instance getter.
func = Dart_LookupFunction(cls, Dart_NewString("c"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("c 0 0 getter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a instance setter.
func = Dart_LookupFunction(cls, Dart_NewString("d="));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("d= 1 0 setter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a private instance getter.
func = Dart_LookupFunction(cls, Dart_NewString("_e"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("_e 0 0 getter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a private instance setter.
func = Dart_LookupFunction(cls, Dart_NewString("_f="));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("_f= 1 0 setter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a static method.
func = Dart_LookupFunction(cls, Dart_NewString("g"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("g 0 0 static", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a private static method.
func = Dart_LookupFunction(cls, Dart_NewString("_h"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("_h 0 0 static", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a static getter.
func = Dart_LookupFunction(cls, Dart_NewString("i"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("i 0 0 static getter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a static setter.
func = Dart_LookupFunction(cls, Dart_NewString("j="));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("j= 1 0 static setter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a private static getter.
func = Dart_LookupFunction(cls, Dart_NewString("_k"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("_k 0 0 static getter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a private static setter.
func = Dart_LookupFunction(cls, Dart_NewString("_l="));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("_l= 1 0 static setter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup an abstract method.
func = Dart_LookupFunction(cls, Dart_NewString("m"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("m 0 0 abstract", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a private abstract method.
func = Dart_LookupFunction(cls, Dart_NewString("_n"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("_n 0 0 abstract", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a abstract getter.
func = Dart_LookupFunction(cls, Dart_NewString("o"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("o 0 0 abstract getter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a abstract setter.
func = Dart_LookupFunction(cls, Dart_NewString("p="));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("p= 1 0 abstract setter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a private abstract getter.
func = Dart_LookupFunction(cls, Dart_NewString("_q"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("_q 0 0 abstract getter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a private abstract setter.
func = Dart_LookupFunction(cls, Dart_NewString("_r="));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("_r= 1 0 abstract setter", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a method with fixed and optional parameters.
func = Dart_LookupFunction(cls, Dart_NewString("s"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("s 1 2", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a method with only optional parameters.
func = Dart_LookupFunction(cls, Dart_NewString("t"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("t 0 3", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup an operator
func = Dart_LookupFunction(cls, Dart_NewString("=="));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
BuildFunctionDescription(&buffer, func);
EXPECT_STREQ("== 1 0", buffer.buf());
owner = Dart_FunctionOwner(func);
EXPECT_VALID(owner);
EXPECT(Dart_IdentityEquals(owner, cls));
// Lookup a function that does not exist from a library.
func = Dart_LookupFunction(lib, Dart_NewString("DoesNotExist"));
EXPECT(Dart_IsNull(func));
// Lookup a function that does not exist from a class.
func = Dart_LookupFunction(cls, Dart_NewString("DoesNotExist"));
EXPECT(Dart_IsNull(func));
// Lookup a class using an error class name. The error propagates.
func = Dart_LookupFunction(cls, Api::NewError("myerror"));
EXPECT_ERROR(func, "myerror");
// Lookup a class from an error library. The error propagates.
func = Dart_LookupFunction(Api::NewError("myerror"), Dart_NewString("foo"));
EXPECT_ERROR(func, "myerror");
}
TEST_CASE(TypeReflection) {
const char* kScriptChars =
"void func(String a, int b) {}\n"
"int variable;\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(lib);
Dart_Handle func = Dart_LookupFunction(lib, Dart_NewString("func"));
EXPECT_VALID(func);
EXPECT(Dart_IsFunction(func));
// Make sure parameter counts are right.
int64_t fixed_params = -1;
int64_t opt_params = -1;
EXPECT_VALID(Dart_FunctionParameterCounts(func, &fixed_params, &opt_params));
EXPECT_EQ(2, fixed_params);
EXPECT_EQ(0, opt_params);
// Check the return type.
Dart_Handle type = Dart_FunctionReturnType(func);
EXPECT_VALID(type);
Dart_Handle cls_name = Dart_ClassName(type);
EXPECT_VALID(cls_name);
const char* cls_name_cstr = "";
EXPECT_VALID(Dart_StringToCString(cls_name, &cls_name_cstr));
EXPECT_STREQ("void", cls_name_cstr);
// Check a parameter type.
type = Dart_FunctionParameterType(func, 0);
EXPECT_VALID(type);
cls_name = Dart_ClassName(type);
EXPECT_VALID(cls_name);
cls_name_cstr = "";
EXPECT_VALID(Dart_StringToCString(cls_name, &cls_name_cstr));
EXPECT_STREQ("String", cls_name_cstr);
Dart_Handle var = Dart_LookupVariable(lib, Dart_NewString("variable"));
EXPECT_VALID(var);
EXPECT(Dart_IsVariable(var));
// Check the variable type.
type = Dart_VariableType(var);
EXPECT_VALID(type);
cls_name = Dart_ClassName(type);
EXPECT_VALID(cls_name);
cls_name_cstr = "";
EXPECT_VALID(Dart_StringToCString(cls_name, &cls_name_cstr));
if (FLAG_enable_type_checks) {
EXPECT_STREQ("int", cls_name_cstr);
} else {
EXPECT_STREQ("Dynamic", cls_name_cstr);
}
}
static void BuildVariableDescription(TextBuffer* buffer, Dart_Handle var) {
buffer->Clear();
Dart_Handle name = Dart_VariableName(var);
EXPECT_VALID(name);
const char* name_cstr = "";
EXPECT_VALID(Dart_StringToCString(name, &name_cstr));
bool is_static = false;
bool is_final = false;
EXPECT_VALID(Dart_VariableIsStatic(var, &is_static));
EXPECT_VALID(Dart_VariableIsFinal(var, &is_final));
buffer->Printf("%s", name_cstr);
if (is_static) {
buffer->Printf(" static");
}
if (is_final) {
buffer->Printf(" final");
}
}
TEST_CASE(VariableReflection) {
const char* kScriptChars =
"var a = 'a';\n"
"var _b = '_b';\n"
"final c = 'c';\n"
"final _d = '_d';\n"
"class MyClass {\n"
" var a = 'a';\n"
" var _b = '_b';\n"
" final c = 'c';\n"
" final _d = '_d';\n"
" static var e = 'e';\n"
" static var _f = '_f';\n"
" static const g = 'g';\n"
" static const _h = '_h';\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(lib);
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("MyClass"));
EXPECT_VALID(cls);
TextBuffer buffer(128);
// Lookup a top-level variable.
Dart_Handle var = Dart_LookupVariable(lib, Dart_NewString("a"));
EXPECT_VALID(var);
EXPECT(Dart_IsVariable(var));
BuildVariableDescription(&buffer, var);
EXPECT_STREQ("a static", buffer.buf());
// Lookup a private top-level variable.
var = Dart_LookupVariable(lib, Dart_NewString("_b"));
EXPECT_VALID(var);
EXPECT(Dart_IsVariable(var));
BuildVariableDescription(&buffer, var);
EXPECT_STREQ("_b static", buffer.buf());
// Lookup a const top-level variable.
var = Dart_LookupVariable(lib, Dart_NewString("c"));
EXPECT_VALID(var);
EXPECT(Dart_IsVariable(var));
BuildVariableDescription(&buffer, var);
EXPECT_STREQ("c static final", buffer.buf());
// Lookup a private const top-level variable.
var = Dart_LookupVariable(lib, Dart_NewString("_d"));
EXPECT_VALID(var);
EXPECT(Dart_IsVariable(var));
BuildVariableDescription(&buffer, var);
EXPECT_STREQ("_d static final", buffer.buf());
// Lookup a instance variable.
var = Dart_LookupVariable(cls, Dart_NewString("a"));
EXPECT_VALID(var);
EXPECT(Dart_IsVariable(var));
BuildVariableDescription(&buffer, var);
EXPECT_STREQ("a", buffer.buf());
// Lookup a private instance variable.
var = Dart_LookupVariable(cls, Dart_NewString("_b"));
EXPECT_VALID(var);
EXPECT(Dart_IsVariable(var));
BuildVariableDescription(&buffer, var);
EXPECT_STREQ("_b", buffer.buf());
// Lookup a final instance variable.
var = Dart_LookupVariable(cls, Dart_NewString("c"));
EXPECT_VALID(var);
EXPECT(Dart_IsVariable(var));
BuildVariableDescription(&buffer, var);
EXPECT_STREQ("c final", buffer.buf());
// Lookup a private final instance variable.
var = Dart_LookupVariable(cls, Dart_NewString("_d"));
EXPECT_VALID(var);
EXPECT(Dart_IsVariable(var));
BuildVariableDescription(&buffer, var);
EXPECT_STREQ("_d final", buffer.buf());
// Lookup a static variable.
var = Dart_LookupVariable(cls, Dart_NewString("e"));
EXPECT_VALID(var);
EXPECT(Dart_IsVariable(var));
BuildVariableDescription(&buffer, var);
EXPECT_STREQ("e static", buffer.buf());
// Lookup a private static variable.
var = Dart_LookupVariable(cls, Dart_NewString("_f"));
EXPECT_VALID(var);
EXPECT(Dart_IsVariable(var));
BuildVariableDescription(&buffer, var);
EXPECT_STREQ("_f static", buffer.buf());
// Lookup a const static variable.
var = Dart_LookupVariable(cls, Dart_NewString("g"));
EXPECT_VALID(var);
EXPECT(Dart_IsVariable(var));
BuildVariableDescription(&buffer, var);
EXPECT_STREQ("g static final", buffer.buf());
// Lookup a private const static variable.
var = Dart_LookupVariable(cls, Dart_NewString("_h"));
EXPECT_VALID(var);
EXPECT(Dart_IsVariable(var));
BuildVariableDescription(&buffer, var);
EXPECT_STREQ("_h static final", buffer.buf());
// Lookup a variable that does not exist from a library.
var = Dart_LookupVariable(lib, Dart_NewString("DoesNotExist"));
EXPECT(Dart_IsNull(var));
// Lookup a variable that does not exist from a class.
var = Dart_LookupVariable(cls, Dart_NewString("DoesNotExist"));
EXPECT(Dart_IsNull(var));
// Lookup a class from an error library. The error propagates.
var = Dart_LookupVariable(Api::NewError("myerror"), Dart_NewString("foo"));
EXPECT_ERROR(var, "myerror");
// Lookup a class using an error class name. The error propagates.
var = Dart_LookupVariable(lib, Api::NewError("myerror"));
EXPECT_ERROR(var, "myerror");
}
TEST_CASE(TypeVariableReflection) {
const char* kScriptChars =
"interface UpperBound {}\n"
"class GenericClass<U, T extends UpperBound> {\n"
" T func1() { return null; }\n"
" U func2() { return null; }\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("GenericClass"));
EXPECT_VALID(cls);
// Test Dart_GetTypeVariableNames.
Dart_Handle names = Dart_GetTypeVariableNames(cls);
EXPECT_VALID(names);
Dart_Handle names_str = Dart_ToString(names);
EXPECT_VALID(names_str);
const char* cstr = "";
EXPECT_VALID(Dart_StringToCString(names_str, &cstr));
EXPECT_STREQ("[U, T]", cstr);
// Test variable U.
Dart_Handle type_var = Dart_LookupTypeVariable(cls, Dart_NewString("U"));
EXPECT_VALID(type_var);
EXPECT(Dart_IsTypeVariable(type_var));
Dart_Handle type_var_name = Dart_TypeVariableName(type_var);
EXPECT_VALID(type_var_name);
EXPECT_VALID(Dart_StringToCString(type_var_name, &cstr));
EXPECT_STREQ("U", cstr);
Dart_Handle type_var_owner = Dart_TypeVariableOwner(type_var);
EXPECT_VALID(type_var_owner);
EXPECT(Dart_IdentityEquals(cls, type_var_owner));
Dart_Handle type_var_bound = Dart_TypeVariableUpperBound(type_var);
Dart_Handle bound_name = Dart_ClassName(type_var_bound);
EXPECT_VALID(Dart_StringToCString(bound_name, &cstr));
EXPECT_STREQ("Object", cstr);
// Test variable T.
type_var = Dart_LookupTypeVariable(cls, Dart_NewString("T"));
EXPECT_VALID(type_var);
EXPECT(Dart_IsTypeVariable(type_var));
type_var_name = Dart_TypeVariableName(type_var);
EXPECT_VALID(type_var_name);
EXPECT_VALID(Dart_StringToCString(type_var_name, &cstr));
EXPECT_STREQ("T", cstr);
type_var_owner = Dart_TypeVariableOwner(type_var);
EXPECT_VALID(type_var_owner);
EXPECT(Dart_IdentityEquals(cls, type_var_owner));
type_var_bound = Dart_TypeVariableUpperBound(type_var);
bound_name = Dart_ClassName(type_var_bound);
EXPECT_VALID(Dart_StringToCString(bound_name, &cstr));
EXPECT_STREQ("UpperBound", cstr);
}
TEST_CASE(InstanceOf) {
const char* kScriptChars =
"class OtherClass {\n"
" static returnNull() { return null; }\n"
"}\n"
"class InstanceOfTest {\n"
" InstanceOfTest() {}\n"
" static InstanceOfTest testMain() {\n"
" return new InstanceOfTest();\n"
" }\n"
"}\n";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Fetch InstanceOfTest class.
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("InstanceOfTest"));
EXPECT_VALID(cls);
// Invoke a function which returns an object of type InstanceOf..
Dart_Handle instanceOfTestObj =
Dart_Invoke(cls, Dart_NewString("testMain"), 0, NULL);
EXPECT_VALID(instanceOfTestObj);
// Now check instanceOfTestObj reported as an instance of
// InstanceOfTest class.
bool is_instance = false;
result = Dart_ObjectIsType(instanceOfTestObj, cls, &is_instance);
EXPECT_VALID(result);
EXPECT(is_instance);
// Fetch OtherClass and check if instanceOfTestObj is instance of it.
Dart_Handle otherClass = Dart_GetClass(lib, Dart_NewString("OtherClass"));
EXPECT_VALID(otherClass);
result = Dart_ObjectIsType(instanceOfTestObj, otherClass, &is_instance);
EXPECT_VALID(result);
EXPECT(!is_instance);
// Check that primitives are not instances of InstanceOfTest class.
result = Dart_ObjectIsType(Dart_NewString("a string"), otherClass,
&is_instance);
EXPECT_VALID(result);
EXPECT(!is_instance);
result = Dart_ObjectIsType(Dart_NewInteger(42), otherClass, &is_instance);
EXPECT_VALID(result);
EXPECT(!is_instance);
result = Dart_ObjectIsType(Dart_NewBoolean(true), otherClass, &is_instance);
EXPECT_VALID(result);
EXPECT(!is_instance);
// Check that null is not an instance of InstanceOfTest class.
Dart_Handle null = Dart_Invoke(otherClass,
Dart_NewString("returnNull"),
0,
NULL);
EXPECT_VALID(null);
result = Dart_ObjectIsType(null, otherClass, &is_instance);
EXPECT_VALID(result);
EXPECT(!is_instance);
// Check that error is returned if null is passed as a class argument.
result = Dart_ObjectIsType(null, null, &is_instance);
EXPECT(Dart_IsError(result));
}
static Dart_Handle library_handler(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url) {
if (tag == kCanonicalizeUrl) {
return url;
}
return Api::Success(Isolate::Current());
}
TEST_CASE(LoadScript) {
const char* kScriptChars =
"main() {"
" return 12345;"
"}";
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle error = Dart_Error("incoming error");
Dart_Handle result;
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
result = Dart_LoadScript(Dart_Null(), source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadScript expects argument 'url' to be non-null.",
Dart_GetError(result));
result = Dart_LoadScript(Dart_True(), source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadScript expects argument 'url' to be of type String.",
Dart_GetError(result));
result = Dart_LoadScript(error, source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LoadScript(url, Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadScript expects argument 'source' to be non-null.",
Dart_GetError(result));
result = Dart_LoadScript(url, Dart_True());
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LoadScript expects argument 'source' to be of type String.",
Dart_GetError(result));
result = Dart_LoadScript(url, error);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
// Load a script successfully.
result = Dart_LoadScript(url, source);
EXPECT_VALID(result);
result = Dart_Invoke(result, Dart_NewString("main"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t value = 0;
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(12345, value);
// Further calls to LoadScript are errors.
result = Dart_LoadScript(url, source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadScript: "
"A script has already been loaded from 'dart:test-lib'.",
Dart_GetError(result));
}
TEST_CASE(RootLibrary) {
const char* kScriptChars =
"main() {"
" return 12345;"
"}";
Dart_Handle root_lib = Dart_RootLibrary();
EXPECT_VALID(root_lib);
EXPECT(Dart_IsNull(root_lib));
// Load a script.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
EXPECT_VALID(Dart_LoadScript(url, source));
root_lib = Dart_RootLibrary();
Dart_Handle lib_name = Dart_LibraryName(root_lib);
EXPECT_VALID(lib_name);
EXPECT(!Dart_IsNull(root_lib));
const char* name_cstr = "";
EXPECT_VALID(Dart_StringToCString(lib_name, &name_cstr));
EXPECT_STREQ(TestCase::url(), name_cstr);
}
static int index = 0;
static Dart_Handle import_library_handler(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url) {
if (tag == kCanonicalizeUrl) {
return url;
}
EXPECT(Dart_IsString(url));
const char* cstr = NULL;
EXPECT_VALID(Dart_StringToCString(url, &cstr));
switch (index) {
case 0:
EXPECT_STREQ("./weird.dart", cstr);
break;
case 1:
EXPECT_STREQ("abclaladef", cstr);
break;
case 2:
EXPECT_STREQ("winner", cstr);
break;
case 3:
EXPECT_STREQ("abclaladef/extra_weird.dart", cstr);
break;
case 4:
EXPECT_STREQ("winnerwinner", cstr);
break;
default:
EXPECT(false);
return Api::NewError("invalid callback");
}
index += 1;
return Api::Success(Isolate::Current());
}
TEST_CASE(LoadScript_CompileError) {
const char* kScriptChars =
")";
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle result = Dart_SetLibraryTagHandler(import_library_handler);
EXPECT_VALID(result);
result = Dart_LoadScript(url, source);
EXPECT(Dart_IsError(result));
EXPECT(strstr(Dart_GetError(result), "unexpected token ')'"));
}
TEST_CASE(LookupLibrary) {
const char* kScriptChars =
"#import('library1.dart');"
"main() {}";
const char* kLibrary1Chars =
"#library('library1.dart');"
"#import('library2.dart');";
// Create a test library and Load up a test script in it.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
result = Dart_LoadScript(url, source);
EXPECT_VALID(result);
url = Dart_NewString("library1.dart");
source = Dart_NewString(kLibrary1Chars);
result = Dart_LoadLibrary(url, source);
EXPECT_VALID(result);
result = Dart_LookupLibrary(url);
EXPECT_VALID(result);
result = Dart_LookupLibrary(Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LookupLibrary expects argument 'url' to be non-null.",
Dart_GetError(result));
result = Dart_LookupLibrary(Dart_True());
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LookupLibrary expects argument 'url' to be of type String.",
Dart_GetError(result));
result = Dart_LookupLibrary(Dart_Error("incoming error"));
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
url = Dart_NewString("noodles.dart");
result = Dart_LookupLibrary(url);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LookupLibrary: library 'noodles.dart' not found.",
Dart_GetError(result));
}
TEST_CASE(LibraryName) {
const char* kLibrary1Chars =
"#library('library1_name');";
Dart_Handle url = Dart_NewString("library1_url");
Dart_Handle source = Dart_NewString(kLibrary1Chars);
Dart_Handle lib = Dart_LoadLibrary(url, source);
Dart_Handle error = Dart_Error("incoming error");
EXPECT_VALID(lib);
Dart_Handle result = Dart_LibraryName(Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LibraryName expects argument 'library' to be non-null.",
Dart_GetError(result));
result = Dart_LibraryName(Dart_True());
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LibraryName expects argument 'library' to be of type Library.",
Dart_GetError(result));
result = Dart_LibraryName(error);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LibraryName(lib);
EXPECT_VALID(result);
EXPECT(Dart_IsString(result));
const char* cstr = NULL;
EXPECT_VALID(Dart_StringToCString(result, &cstr));
EXPECT_STREQ("library1_name", cstr);
}
TEST_CASE(LibraryUrl) {
const char* kLibrary1Chars =
"#library('library1_name');";
Dart_Handle url = Dart_NewString("library1_url");
Dart_Handle source = Dart_NewString(kLibrary1Chars);
Dart_Handle lib = Dart_LoadLibrary(url, source);
Dart_Handle error = Dart_Error("incoming error");
EXPECT_VALID(lib);
Dart_Handle result = Dart_LibraryUrl(Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LibraryUrl expects argument 'library' to be non-null.",
Dart_GetError(result));
result = Dart_LibraryUrl(Dart_True());
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LibraryUrl expects argument 'library' to be of type Library.",
Dart_GetError(result));
result = Dart_LibraryUrl(error);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LibraryUrl(lib);
EXPECT_VALID(result);
EXPECT(Dart_IsString(result));
const char* cstr = NULL;
EXPECT_VALID(Dart_StringToCString(result, &cstr));
EXPECT_STREQ("library1_url", cstr);
}
TEST_CASE(LibraryGetClassNames) {
const char* kLibraryChars =
"#library('library_name');\n"
"\n"
"class A {}\n"
"class B {}\n"
"interface C {}\n"
"class _A {}\n"
"class _B {}\n"
"interface _C {}\n"
"\n"
"_compare(String a, String b) => a.compareTo(b);\n"
"sort(list) => list.sort(_compare);\n";
Dart_Handle url = Dart_NewString("library_url");
Dart_Handle source = Dart_NewString(kLibraryChars);
Dart_Handle lib = Dart_LoadLibrary(url, source);
EXPECT_VALID(lib);
Dart_Handle list = Dart_LibraryGetClassNames(lib);
EXPECT_VALID(list);
EXPECT(Dart_IsList(list));
// Sort the list.
const int kNumArgs = 1;
Dart_Handle args[1];
args[0] = list;
EXPECT_VALID(Dart_Invoke(lib, Dart_NewString("sort"), kNumArgs, args));
Dart_Handle list_string = Dart_ToString(list);
EXPECT_VALID(list_string);
const char* list_cstr = "";
EXPECT_VALID(Dart_StringToCString(list_string, &list_cstr));
EXPECT_STREQ("[A, B, C, _A, _B, _C]", list_cstr);
}
TEST_CASE(GetFunctionNames) {
const char* kLibraryChars =
"#library('library_name');\n"
"\n"
"void A() {}\n"
"get B => 11;\n"
"set C(x) { }\n"
"var D;\n"
"void _A() {}\n"
"get _B => 11;\n"
"set _C(x) { }\n"
"var _D;\n"
"\n"
"class MyClass {\n"
" void A2() {}\n"
" get B2 => 11;\n"
" set C2(x) { }\n"
" var D2;\n"
" void _A2() {}\n"
" get _B2 => 11;\n"
" set _C2(x) { }\n"
" var _D2;\n"
"}\n"
"\n"
"_compare(String a, String b) => a.compareTo(b);\n"
"sort(list) => list.sort(_compare);\n";
// Get the functions from a library.
Dart_Handle url = Dart_NewString("library_url");
Dart_Handle source = Dart_NewString(kLibraryChars);
Dart_Handle lib = Dart_LoadLibrary(url, source);
EXPECT_VALID(lib);
Dart_Handle list = Dart_GetFunctionNames(lib);
EXPECT_VALID(list);
EXPECT(Dart_IsList(list));
// Sort the list.
const int kNumArgs = 1;
Dart_Handle args[1];
args[0] = list;
EXPECT_VALID(Dart_Invoke(lib, Dart_NewString("sort"), kNumArgs, args));
Dart_Handle list_string = Dart_ToString(list);
EXPECT_VALID(list_string);
const char* list_cstr = "";
EXPECT_VALID(Dart_StringToCString(list_string, &list_cstr));
EXPECT_STREQ("[A, B, C=, _A, _B, _C=, _compare, sort]", list_cstr);
// Get the functions from a class.
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("MyClass"));
EXPECT_VALID(cls);
list = Dart_GetFunctionNames(cls);
EXPECT_VALID(list);
EXPECT(Dart_IsList(list));
// Sort the list.
args[0] = list;
EXPECT_VALID(Dart_Invoke(lib, Dart_NewString("sort"), kNumArgs, args));
// Check list contents.
list_string = Dart_ToString(list);
EXPECT_VALID(list_string);
list_cstr = "";
EXPECT_VALID(Dart_StringToCString(list_string, &list_cstr));
EXPECT_STREQ("[A2, B2, C2=, MyClass, _A2, _B2, _C2=]", list_cstr);
}
TEST_CASE(GetVariableNames) {
const char* kLibraryChars =
"#library('library_name');\n"
"\n"
"var A;\n"
"get B => 12;\n"
"set C(x) { }\n"
"D(x) => (x + 1);\n"
"var _A;\n"
"get _B => 12;\n"
"set _C(x) { }\n"
"_D(x) => (x + 1);\n"
"\n"
"class MyClass {\n"
" var A2;\n"
" var _A2;\n"
"}\n"
"\n"
"_compare(String a, String b) => a.compareTo(b);\n"
"sort(list) => list.sort(_compare);\n";
// Get the variables from a library.
Dart_Handle url = Dart_NewString("library_url");
Dart_Handle source = Dart_NewString(kLibraryChars);
Dart_Handle lib = Dart_LoadLibrary(url, source);
EXPECT_VALID(lib);
Dart_Handle list = Dart_GetVariableNames(lib);
EXPECT_VALID(list);
EXPECT(Dart_IsList(list));
// Sort the list.
const int kNumArgs = 1;
Dart_Handle args[1];
args[0] = list;
EXPECT_VALID(Dart_Invoke(lib, Dart_NewString("sort"), kNumArgs, args));
// Check list contents.
Dart_Handle list_string = Dart_ToString(list);
EXPECT_VALID(list_string);
const char* list_cstr = "";
EXPECT_VALID(Dart_StringToCString(list_string, &list_cstr));
EXPECT_STREQ("[A, _A]", list_cstr);
// Get the variables from a class.
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("MyClass"));
EXPECT_VALID(cls);
list = Dart_GetVariableNames(cls);
EXPECT_VALID(list);
EXPECT(Dart_IsList(list));
// Sort the list.
args[0] = list;
EXPECT_VALID(Dart_Invoke(lib, Dart_NewString("sort"), kNumArgs, args));
// Check list contents.
list_string = Dart_ToString(list);
EXPECT_VALID(list_string);
list_cstr = "";
EXPECT_VALID(Dart_StringToCString(list_string, &list_cstr));
EXPECT_STREQ("[A2, _A2]", list_cstr);
}
TEST_CASE(LibraryImportLibrary) {
const char* kLibrary1Chars =
"#library('library1_name');";
const char* kLibrary2Chars =
"#library('library2_name');";
Dart_Handle error = Dart_Error("incoming error");
Dart_Handle result;
Dart_Handle url = Dart_NewString("library1_url");
Dart_Handle source = Dart_NewString(kLibrary1Chars);
Dart_Handle lib1 = Dart_LoadLibrary(url, source);
EXPECT_VALID(lib1);
url = Dart_NewString("library2_url");
source = Dart_NewString(kLibrary2Chars);
Dart_Handle lib2 = Dart_LoadLibrary(url, source);
EXPECT_VALID(lib2);
result = Dart_LibraryImportLibrary(Dart_Null(), lib2, Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LibraryImportLibrary expects argument 'library' to be non-null.",
Dart_GetError(result));
result = Dart_LibraryImportLibrary(Dart_True(), lib2, Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LibraryImportLibrary expects argument 'library' to be of "
"type Library.",
Dart_GetError(result));
result = Dart_LibraryImportLibrary(error, lib2, Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LibraryImportLibrary(lib1, Dart_Null(), Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LibraryImportLibrary expects argument 'import' to be non-null.",
Dart_GetError(result));
result = Dart_LibraryImportLibrary(lib1, Dart_True(), Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LibraryImportLibrary expects argument 'import' to be of "
"type Library.",
Dart_GetError(result));
result = Dart_LibraryImportLibrary(lib1, error, Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LibraryImportLibrary(lib1, lib2, Dart_Null());
EXPECT_VALID(result);
}
TEST_CASE(ImportLibraryWithPrefix) {
const char* kLibrary1Chars =
"#library('library1_name');"
"int bar() => 42;";
Dart_Handle url1 = Dart_NewString("library1_url");
Dart_Handle source1 = Dart_NewString(kLibrary1Chars);
Dart_Handle lib1 = Dart_LoadLibrary(url1, source1);
EXPECT_VALID(lib1);
EXPECT(Dart_IsLibrary(lib1));
const char* kLibrary2Chars =
"#library('library2_name');"
"int foobar() => foo.bar();";
Dart_Handle url2 = Dart_NewString("library2_url");
Dart_Handle source2 = Dart_NewString(kLibrary2Chars);
Dart_Handle lib2 = Dart_LoadLibrary(url2, source2);
EXPECT_VALID(lib2);
EXPECT(Dart_IsLibrary(lib2));
Dart_Handle prefix = Dart_NewString("foo");
Dart_Handle result = Dart_LibraryImportLibrary(lib2, lib1, prefix);
EXPECT_VALID(result);
// Lib1 is imported under a library prefix and therefore 'foo' should
// not be found directly in lib2.
Dart_Handle method_name = Dart_NewString("foo");
result = Dart_Invoke(lib2, method_name, 0, NULL);
EXPECT_ERROR(result, "Dart_Invoke: did not find top-level function 'foo'");
// Check that lib1 is available under the prefix in lib2.
method_name = Dart_NewString("foobar");
result = Dart_Invoke(lib2, method_name, 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t value = 0;
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(42, value);
}
TEST_CASE(LoadLibrary) {
const char* kLibrary1Chars =
"#library('library1_name');";
Dart_Handle error = Dart_Error("incoming error");
Dart_Handle result;
Dart_Handle url = Dart_NewString("library1_url");
Dart_Handle source = Dart_NewString(kLibrary1Chars);
result = Dart_LoadLibrary(Dart_Null(), source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadLibrary expects argument 'url' to be non-null.",
Dart_GetError(result));
result = Dart_LoadLibrary(Dart_True(), source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadLibrary expects argument 'url' to be of type String.",
Dart_GetError(result));
result = Dart_LoadLibrary(error, source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LoadLibrary(url, Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadLibrary expects argument 'source' to be non-null.",
Dart_GetError(result));
result = Dart_LoadLibrary(url, Dart_True());
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LoadLibrary expects argument 'source' to be of type String.",
Dart_GetError(result));
result = Dart_LoadLibrary(url, error);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
// Success.
result = Dart_LoadLibrary(url, source);
EXPECT_VALID(result);
EXPECT(Dart_IsLibrary(result));
// Duplicate library load fails.
result = Dart_LoadLibrary(url, source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LoadLibrary: library 'library1_url' has already been loaded.",
Dart_GetError(result));
}
TEST_CASE(LoadLibrary_CompileError) {
const char* kLibrary1Chars =
"#library('library1_name');"
")";
Dart_Handle url = Dart_NewString("library1_url");
Dart_Handle source = Dart_NewString(kLibrary1Chars);
Dart_Handle result = Dart_LoadLibrary(url, source);
EXPECT(Dart_IsError(result));
EXPECT(strstr(Dart_GetError(result), "unexpected token ')'"));
}
TEST_CASE(LoadSource) {
const char* kLibrary1Chars =
"#library('library1_name');";
const char* kSourceChars =
"// Something innocuous";
const char* kBadSourceChars =
")";
Dart_Handle error = Dart_Error("incoming error");
Dart_Handle result;
// Load up a library.
Dart_Handle url = Dart_NewString("library1_url");
Dart_Handle source = Dart_NewString(kLibrary1Chars);
Dart_Handle lib = Dart_LoadLibrary(url, source);
EXPECT_VALID(lib);
EXPECT(Dart_IsLibrary(lib));
url = Dart_NewString("source_url");
source = Dart_NewString(kSourceChars);
result = Dart_LoadSource(Dart_Null(), url, source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadSource expects argument 'library' to be non-null.",
Dart_GetError(result));
result = Dart_LoadSource(Dart_True(), url, source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LoadSource expects argument 'library' to be of type Library.",
Dart_GetError(result));
result = Dart_LoadSource(error, url, source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LoadSource(lib, Dart_Null(), source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadSource expects argument 'url' to be non-null.",
Dart_GetError(result));
result = Dart_LoadSource(lib, Dart_True(), source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadSource expects argument 'url' to be of type String.",
Dart_GetError(result));
result = Dart_LoadSource(lib, error, source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LoadSource(lib, url, Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadSource expects argument 'source' to be non-null.",
Dart_GetError(result));
result = Dart_LoadSource(lib, url, Dart_True());
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LoadSource expects argument 'source' to be of type String.",
Dart_GetError(result));
result = Dart_LoadSource(lib, error, source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
// Success.
result = Dart_LoadSource(lib, url, source);
EXPECT_VALID(result);
EXPECT(Dart_IsLibrary(result));
EXPECT(Dart_IdentityEquals(lib, result));
// Duplicate calls are okay.
result = Dart_LoadSource(lib, url, source);
EXPECT_VALID(result);
EXPECT(Dart_IsLibrary(result));
EXPECT(Dart_IdentityEquals(lib, result));
// Language errors are detected.
source = Dart_NewString(kBadSourceChars);
result = Dart_LoadSource(lib, url, source);
EXPECT(Dart_IsError(result));
}
TEST_CASE(LoadSource_LateLoad) {
const char* kLibrary1Chars =
"#library('library1_name');\n"
"class OldClass {\n"
" foo() => 'foo';\n"
"}\n";
const char* kSourceChars =
"class NewClass extends OldClass{\n"
" bar() => 'bar';\n"
"}\n";
Dart_Handle url = Dart_NewString("library1_url");
Dart_Handle source = Dart_NewString(kLibrary1Chars);
Dart_Handle lib = Dart_LoadLibrary(url, source);
EXPECT_VALID(lib);
EXPECT(Dart_IsLibrary(lib));
// Call a dynamic function on OldClass.
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("OldClass"));
EXPECT_VALID(cls);
Dart_Handle recv = Dart_New(cls, Dart_Null(), 0, NULL);
Dart_Handle result = Dart_Invoke(recv, Dart_NewString("foo"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsString(result));
const char* result_cstr = "";
EXPECT_VALID(Dart_StringToCString(result, &result_cstr));
EXPECT_STREQ("foo", result_cstr);
// Load a source file late.
url = Dart_NewString("source_url");
source = Dart_NewString(kSourceChars);
EXPECT_VALID(Dart_LoadSource(lib, url, source));
// Call a dynamic function on NewClass in the updated library.
cls = Dart_GetClass(lib, Dart_NewString("NewClass"));
EXPECT_VALID(cls);
recv = Dart_New(cls, Dart_Null(), 0, NULL);
result = Dart_Invoke(recv, Dart_NewString("bar"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsString(result));
result_cstr = "";
EXPECT_VALID(Dart_StringToCString(result, &result_cstr));
EXPECT_STREQ("bar", result_cstr);
}
static void PatchNativeFunction(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_SetReturnValue(args, Dart_Null());
Dart_ExitScope();
}
static Dart_NativeFunction PatchNativeResolver(Dart_Handle name,
int arg_count) {
return &PatchNativeFunction;
}
TEST_CASE(ParsePatchLibrary) {
const char* kLibraryChars =
"#library('patched_library');\n"
"class A {\n"
" final fvalue;\n"
" var _f;\n"
" callFunc(x, y) => x(y);\n"
" external method(var value);\n"
" get field => _field;\n"
"}\n"
"class B {\n"
" var val;\n"
" external B.named(x);\n"
" external B(v);\n"
"}\n"
"external int unpatched();\n"
"external int topLevel(var value);\n"
"external int get topLevelGetter;\n"
"external void set topLevelSetter(int value);\n";
const char* kPatchChars =
"patch class A {\n"
" var _g;\n"
" A() : fvalue = 13;\n"
" get _field => _g;\n"
" patch method(var value) {\n"
" int closeYourEyes(var eggs) { return eggs * -1; }\n"
" value = callFunc(closeYourEyes, value);\n"
" _g = value * 5;\n"
" }\n"
"}\n"
"patch class B {\n"
" B._internal(x) : val = x;\n"
" /*patch*/ factory B.named(x) { return new B._internal(x); }\n"
" /*patch*/ factory B(v) native \"const_B_factory\";\n"
"}\n"
"var _topLevelValue = -1;\n"
"patch int topLevel(var value) => value * value;\n"
"patch int set topLevelSetter(value) { _topLevelValue = value; }\n"
"patch int get topLevelGetter => 2 * _topLevelValue;\n"
// Allow top level methods named patch.
"patch(x) => x*3;\n";
const char* kScriptChars =
"#import('theLibrary');\n"
"e1() => unpatched();\n"
"m1() => topLevel(2);\n"
"m2() {\n"
" topLevelSetter = 20;\n"
" return topLevelGetter;\n"
"}\n"
"m3() => patch(7);\n"
"m4() {\n"
" var a = new A();\n"
" a.method(5);\n"
" return a.field;\n"
"}\n"
"m5() => new B(3);\n"
"m6() {\n"
" var b = new B.named(8);\n"
" return b.val;\n"
"}\n"
; // NOLINT
Dart_Handle result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
Dart_Handle url = Dart_NewString("theLibrary");
Dart_Handle source = Dart_NewString(kLibraryChars);
result = Dart_LoadLibrary(url, source);
EXPECT_VALID(result);
const String& patch_url = String::Handle(String::New("theLibrary patch"));
const String& patch_source = String::Handle(String::New(kPatchChars));
const Script& patch_script = Script::Handle(Script::New(
patch_url, patch_source, RawScript::kPatchTag));
const String& lib_url = String::Handle(String::New("theLibrary"));
const Library& lib = Library::Handle(Library::LookupLibrary(lib_url));
const Error& err = Error::Handle(lib.Patch(patch_script));
if (!err.IsNull()) {
OS::Print("Patching error: %s\n", err.ToErrorCString());
EXPECT(false);
}
result = Dart_SetNativeResolver(result, &PatchNativeResolver);
EXPECT_VALID(result);
Dart_Handle script_url = Dart_NewString("theScript");
source = Dart_NewString(kScriptChars);
Dart_Handle test_script = Dart_LoadScript(script_url, source);
EXPECT_VALID(test_script);
// Make sure that we can compile all of the patched code.
result = Dart_CompileAll();
EXPECT_VALID(result);
result = Dart_Invoke(test_script, Dart_NewString("e1"), 0, NULL);
EXPECT_ERROR(result, "External implementation missing");
int64_t value = 0;
result = Dart_Invoke(test_script, Dart_NewString("m1"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(4, value);
value = 0;
result = Dart_Invoke(test_script, Dart_NewString("m2"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(40, value);
value = 0;
result = Dart_Invoke(test_script, Dart_NewString("m3"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(21, value);
value = 0;
result = Dart_Invoke(test_script, Dart_NewString("m4"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(-25, value);
result = Dart_Invoke(test_script, Dart_NewString("m5"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsNull(result));
value = 0;
result = Dart_Invoke(test_script, Dart_NewString("m6"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(8, value);
}
static void MyNativeFunction1(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_SetReturnValue(args, Dart_NewInteger(654321));
Dart_ExitScope();
}
static void MyNativeFunction2(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_SetReturnValue(args, Dart_NewInteger(123456));
Dart_ExitScope();
}
static Dart_NativeFunction MyNativeResolver1(Dart_Handle name,
int arg_count) {
return &MyNativeFunction1;
}
static Dart_NativeFunction MyNativeResolver2(Dart_Handle name,
int arg_count) {
return &MyNativeFunction2;
}
TEST_CASE(SetNativeResolver) {
const char* kScriptChars =
"class Test {"
" static foo() native \"SomeNativeFunction\";"
" static bar() native \"SomeNativeFunction2\";"
" static baz() native \"SomeNativeFunction3\";"
"}";
Dart_Handle error = Dart_Error("incoming error");
Dart_Handle result;
// Load a test script.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
Dart_Handle lib = Dart_LoadScript(url, source);
EXPECT_VALID(lib);
EXPECT(Dart_IsLibrary(lib));
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("Test"));
EXPECT_VALID(cls);
result = Dart_SetNativeResolver(Dart_Null(), &MyNativeResolver1);
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_SetNativeResolver expects argument 'library' to be non-null.",
Dart_GetError(result));
result = Dart_SetNativeResolver(Dart_True(), &MyNativeResolver1);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_SetNativeResolver expects argument 'library' to be of "
"type Library.",
Dart_GetError(result));
result = Dart_SetNativeResolver(error, &MyNativeResolver1);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_SetNativeResolver(lib, &MyNativeResolver1);
EXPECT_VALID(result);
// Call a function and make sure native resolution works.
result = Dart_Invoke(cls, Dart_NewString("foo"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t value = 0;
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(654321, value);
// A second call succeeds.
result = Dart_SetNativeResolver(lib, &MyNativeResolver2);
EXPECT_VALID(result);
// 'foo' has already been resolved so gets the old value.
result = Dart_Invoke(cls, Dart_NewString("foo"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
value = 0;
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(654321, value);
// 'bar' has not yet been resolved so gets the new value.
result = Dart_Invoke(cls, Dart_NewString("bar"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
value = 0;
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(123456, value);
// A NULL resolver is okay, but resolution will fail.
result = Dart_SetNativeResolver(lib, NULL);
EXPECT_VALID(result);
EXPECT_ERROR(Dart_Invoke(cls, Dart_NewString("baz"), 0, NULL),
"native function 'SomeNativeFunction3' cannot be found");
}
// Test that an imported name does not clash with the same name defined
// in the importing library.
TEST_CASE(ImportLibrary2) {
const char* kScriptChars =
"#import('library1.dart');\n"
"var foo;\n"
"main() { foo = 0; }\n";
const char* kLibrary1Chars =
"#library('library1.dart');\n"
"#import('library2.dart');\n"
"var foo;\n";
const char* kLibrary2Chars =
"#library('library2.dart');\n"
"#import('library1.dart');\n"
"var foo;\n";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
result = Dart_LoadScript(url, source);
url = Dart_NewString("library1.dart");
source = Dart_NewString(kLibrary1Chars);
Dart_LoadLibrary(url, source);
url = Dart_NewString("library2.dart");
source = Dart_NewString(kLibrary2Chars);
Dart_LoadLibrary(url, source);
result = Dart_Invoke(result, Dart_NewString("main"), 0, NULL);
EXPECT_VALID(result);
}
// Test that if the same name is imported from two libraries, it is
// an error if that name is referenced.
TEST_CASE(ImportLibrary3) {
const char* kScriptChars =
"#import('library2.dart');\n"
"#import('library1.dart');\n"
"var foo_top = 10; // foo has dup def. So should be an error.\n"
"main() { foo = 0; }\n";
const char* kLibrary1Chars =
"#library('library1.dart');\n"
"var foo;";
const char* kLibrary2Chars =
"#library('library2.dart');\n"
"var foo;";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
result = Dart_LoadScript(url, source);
EXPECT_VALID(result);
url = Dart_NewString("library2.dart");
source = Dart_NewString(kLibrary2Chars);
Dart_LoadLibrary(url, source);
url = Dart_NewString("library1.dart");
source = Dart_NewString(kLibrary1Chars);
Dart_LoadLibrary(url, source);
result = Dart_Invoke(result, Dart_NewString("main"), 0, NULL);
EXPECT(Dart_IsError(result));
EXPECT_SUBSTRING("ambiguous reference: 'foo'", Dart_GetError(result));
}
// Test that if the same name is imported from two libraries, it is
// not an error if that name is not used.
TEST_CASE(ImportLibrary4) {
const char* kScriptChars =
"#import('library2.dart');\n"
"#import('library1.dart');\n"
"main() { }\n";
const char* kLibrary1Chars =
"#library('library1.dart');\n"
"var foo;";
const char* kLibrary2Chars =
"#library('library2.dart');\n"
"var foo;";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
result = Dart_LoadScript(url, source);
EXPECT_VALID(result);
url = Dart_NewString("library2.dart");
source = Dart_NewString(kLibrary2Chars);
Dart_LoadLibrary(url, source);
url = Dart_NewString("library1.dart");
source = Dart_NewString(kLibrary1Chars);
Dart_LoadLibrary(url, source);
result = Dart_Invoke(result, Dart_NewString("main"), 0, NULL);
EXPECT_VALID(result);
}
TEST_CASE(ImportLibrary5) {
const char* kScriptChars =
"#import('lib.dart');\n"
"interface Y {\n"
" void set handler(void callback(List<int> x));\n"
"}\n"
"void main() {}\n";
const char* kLibraryChars =
"#library('lib.dart');\n"
"interface X {\n"
" void set handler(void callback(List<int> x));\n"
"}\n";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
result = Dart_LoadScript(url, source);
url = Dart_NewString("lib.dart");
source = Dart_NewString(kLibraryChars);
Dart_LoadLibrary(url, source);
result = Dart_Invoke(result, Dart_NewString("main"), 0, NULL);
EXPECT_VALID(result);
}
void NewNativePort_send123(Dart_Port dest_port_id,
Dart_Port reply_port_id,
Dart_CObject *message) {
// Gets a null message.
EXPECT_NOTNULL(message);
EXPECT_EQ(Dart_CObject::kNull, message->type);
// Post integer value.
Dart_CObject* response =
reinterpret_cast<Dart_CObject*>(Dart_ScopeAllocate(sizeof(Dart_CObject)));
response->type = Dart_CObject::kInt32;
response->value.as_int32 = 123;
Dart_PostCObject(reply_port_id, response);
}
void NewNativePort_send321(Dart_Port dest_port_id,
Dart_Port reply_port_id,
Dart_CObject* message) {
// Gets a null message.
EXPECT_NOTNULL(message);
EXPECT_EQ(Dart_CObject::kNull, message->type);
// Post integer value.
Dart_CObject* response =
reinterpret_cast<Dart_CObject*>(Dart_ScopeAllocate(sizeof(Dart_CObject)));
response->type = Dart_CObject::kInt32;
response->value.as_int32 = 321;
Dart_PostCObject(reply_port_id, response);
}
UNIT_TEST_CASE(NewNativePort) {
// Create a port with a bogus handler.
Dart_Port error_port = Dart_NewNativePort("Foo", NULL, true);
EXPECT_EQ(ILLEGAL_PORT, error_port);
// Create the port w/o a current isolate, just to make sure that works.
Dart_Port port_id1 =
Dart_NewNativePort("Port123", NewNativePort_send123, true);
TestIsolateScope __test_isolate__;
const char* kScriptChars =
"#import('dart:isolate');\n"
"void callPort(SendPort port) {\n"
" port.call(null).then((message) {\n"
" throw new Exception(message);\n"
" });\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_EnterScope();
// Create a port w/ a current isolate, to make sure that works too.
Dart_Port port_id2 =
Dart_NewNativePort("Port321", NewNativePort_send321, true);
Dart_Handle send_port1 = Dart_NewSendPort(port_id1);
EXPECT_VALID(send_port1);
Dart_Handle send_port2 = Dart_NewSendPort(port_id2);
EXPECT_VALID(send_port2);
// Test first port.
Dart_Handle dart_args[1];
dart_args[0] = send_port1;
Dart_Handle result =
Dart_Invoke(lib, Dart_NewString("callPort"), 1, dart_args);
EXPECT_VALID(result);
result = Dart_RunLoop();
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result));
EXPECT_SUBSTRING("Exception: 123\n", Dart_GetError(result));
// result second port.
dart_args[0] = send_port2;
result = Dart_Invoke(lib, Dart_NewString("callPort"), 1, dart_args);
EXPECT_VALID(result);
result = Dart_RunLoop();
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result));
EXPECT_SUBSTRING("Exception: 321\n", Dart_GetError(result));
Dart_ExitScope();
// Delete the native ports.
EXPECT(Dart_CloseNativePort(port_id1));
EXPECT(Dart_CloseNativePort(port_id2));
}
static bool RunLoopTestCallback(const char* script_name,
const char* main,
void* data,
char** error) {
const char* kScriptChars =
"#import('builtin');\n"
"#import('dart:isolate');\n"
"void entry() {\n"
" port.receive((message, replyTo) {\n"
" if (message) {\n"
" throw new Exception('MakeChildExit');\n"
" } else {\n"
" replyTo.call('hello');\n"
" port.close();\n"
" }\n"
" });\n"
"}\n"
"\n"
"void main(exc_child, exc_parent) {\n"
" var port = spawnFunction(entry);\n"
" port.call(exc_child).then((message) {\n"
" if (message != 'hello') throw new Exception('ShouldNotHappen');\n"
" if (exc_parent) throw new Exception('MakeParentExit');\n"
" });\n"
"}\n";
if (Dart_CurrentIsolate() != NULL) {
Dart_ExitIsolate();
}
Dart_Isolate isolate = TestCase::CreateTestIsolate();
ASSERT(isolate != NULL);
Dart_EnterScope();
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle result = Dart_SetLibraryTagHandler(TestCase::library_handler);
EXPECT_VALID(result);
Dart_Handle lib = Dart_LoadScript(url, source);
EXPECT_VALID(lib);
Dart_ExitScope();
return true;
}
// Common code for RunLoop_Success/RunLoop_Failure.
static void RunLoopTest(bool throw_exception_child,
bool throw_exception_parent) {
Dart_IsolateCreateCallback saved = Isolate::CreateCallback();
Isolate::SetCreateCallback(RunLoopTestCallback);
RunLoopTestCallback(NULL, NULL, NULL, NULL);
Dart_EnterScope();
Dart_Handle lib = Dart_LookupLibrary(Dart_NewString(TestCase::url()));
EXPECT_VALID(lib);
Dart_Handle result;
Dart_Handle args[2];
args[0] = (throw_exception_child ? Dart_True() : Dart_False());
args[1] = (throw_exception_parent ? Dart_True() : Dart_False());
result = Dart_Invoke(lib, Dart_NewString("main"), 2, args);
EXPECT_VALID(result);
result = Dart_RunLoop();
if (throw_exception_parent) {
EXPECT_ERROR(result, "Exception: MakeParentExit");
} else {
EXPECT_VALID(result);
}
Dart_ExitScope();
Dart_ShutdownIsolate();
Isolate::SetCreateCallback(saved);
}
UNIT_TEST_CASE(RunLoop_Success) {
RunLoopTest(false, false);
}
// This test exits the vm. Listed as FAIL in vm.status.
UNIT_TEST_CASE(RunLoop_ExceptionChild) {
RunLoopTest(true, false);
}
UNIT_TEST_CASE(RunLoop_ExceptionParent) {
RunLoopTest(false, true);
}
// Utility functions and variables for test case IsolateInterrupt starts here.
static Monitor* sync = NULL;
static Dart_Isolate shared_isolate = NULL;
static bool main_entered = false;
void MarkMainEntered(Dart_NativeArguments args) {
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
// Indicate that main has been entered.
{
MonitorLocker ml(sync);
main_entered = true;
ml.Notify();
}
Dart_SetReturnValue(args, Dart_Null());
Dart_ExitScope();
}
static Dart_NativeFunction IsolateInterruptTestNativeLookup(
Dart_Handle name, int argument_count) {
return reinterpret_cast<Dart_NativeFunction>(&MarkMainEntered);
}
void BusyLoop_start(uword unused) {
const char* kScriptChars =
"class Native {\n"
" static void markMainEntered() native 'MarkMainEntered';\n"
"}\n"
"\n"
"void main() {\n"
" Native.markMainEntered();\n"
" while (true) {\n" // Infinite empty loop.
" }\n"
"}\n";
// Tell the other thread that shared_isolate is created.
Dart_Handle lib;
{
sync->Enter();
char* error = NULL;
shared_isolate = Dart_CreateIsolate(NULL, NULL, NULL, NULL, &error);
EXPECT(shared_isolate != NULL);
Dart_EnterScope();
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle result = Dart_SetLibraryTagHandler(TestCase::library_handler);
EXPECT_VALID(result);
lib = Dart_LoadScript(url, source);
EXPECT_VALID(lib);
result = Dart_SetNativeResolver(lib, &IsolateInterruptTestNativeLookup);
DART_CHECK_VALID(result);
sync->Notify();
sync->Exit();
}
Dart_Handle result = Dart_Invoke(lib, Dart_NewString("main"), 0, NULL);
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result));
EXPECT_SUBSTRING("Unhandled exception:\nfoo\n",
Dart_GetError(result));
Dart_ExitScope();
Dart_ShutdownIsolate();
// Tell the other thread that we are done (don't use MonitorLocker
// as there is no current isolate any more).
sync->Enter();
shared_isolate = NULL;
sync->Notify();
sync->Exit();
}
// This callback handles isolate interrupts for the IsolateInterrupt
// test. It ignores the first two interrupts and throws an exception
// on the third interrupt.
const int kInterruptCount = 10;
static int interrupt_count = 0;
static bool IsolateInterruptTestCallback() {
OS::Print(" ========== Interrupt callback called #%d\n", interrupt_count + 1);
{
MonitorLocker ml(sync);
interrupt_count++;
ml.Notify();
}
if (interrupt_count == kInterruptCount) {
Dart_EnterScope();
Dart_Handle lib = Dart_LookupLibrary(Dart_NewString(TestCase::url()));
EXPECT_VALID(lib);
Dart_Handle exc = Dart_NewString("foo");
EXPECT_VALID(exc);
Dart_Handle result = Dart_ThrowException(exc);
EXPECT_VALID(result);
UNREACHABLE(); // Dart_ThrowException only returns if it gets an error.
return false;
}
ASSERT(interrupt_count < kInterruptCount);
return true;
}
TEST_CASE(IsolateInterrupt) {
Dart_IsolateInterruptCallback saved = Isolate::InterruptCallback();
Isolate::SetInterruptCallback(IsolateInterruptTestCallback);
sync = new Monitor();
int result = Thread::Start(BusyLoop_start, 0);
EXPECT_EQ(0, result);
{
MonitorLocker ml(sync);
// Wait for the other isolate to enter main.
while (!main_entered) {
ml.Wait();
}
}
// Send a number of interrupts to the other isolate. All but the
// last allow execution to continue. The last causes an exception in
// the isolate.
for (int i = 0; i < kInterruptCount; i++) {
// Space out the interrupts a bit.
OS::Sleep(i + 1);
Dart_InterruptIsolate(shared_isolate);
{
MonitorLocker ml(sync);
// Wait for interrupt_count to be increased.
while (interrupt_count == i) {
ml.Wait();
}
OS::Print(" ========== Interrupt processed #%d\n", interrupt_count);
}
}
{
MonitorLocker ml(sync);
// Wait for our isolate to finish.
while (shared_isolate != NULL) {
ml.Wait();
}
}
// We should have received the expected number of interrupts.
EXPECT_EQ(kInterruptCount, interrupt_count);
Isolate::SetInterruptCallback(saved);
}
static void* saved_callback_data;
static void IsolateShutdownTestCallback(void* callback_data) {
saved_callback_data = callback_data;
}
UNIT_TEST_CASE(IsolateShutdown) {
Dart_IsolateShutdownCallback saved = Isolate::ShutdownCallback();
Isolate::SetShutdownCallback(IsolateShutdownTestCallback);
saved_callback_data = NULL;
void* my_data = reinterpret_cast<void*>(12345);
// Create an isolate.
char* err;
Dart_Isolate isolate = Dart_CreateIsolate(NULL, NULL, NULL, my_data, &err);
if (isolate == NULL) {
OS::Print("Creation of isolate failed '%s'\n", err);
free(err);
}
EXPECT(isolate != NULL);
// The shutdown callback has not been called.
EXPECT_EQ(0, reinterpret_cast<intptr_t>(saved_callback_data));
// Shutdown the isolate.
Dart_ShutdownIsolate();
// The shutdown callback has been called.
EXPECT_EQ(12345, reinterpret_cast<intptr_t>(saved_callback_data));
Isolate::SetShutdownCallback(saved);
}
static int64_t GetValue(Dart_Handle arg) {
EXPECT_VALID(arg);
EXPECT(Dart_IsInteger(arg));
int64_t value;
EXPECT_VALID(Dart_IntegerToInt64(arg, &value));
return value;
}
static void NativeFoo1(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t i = Dart_GetNativeArgumentCount(args);
EXPECT_EQ(1, i);
Dart_Handle arg = Dart_GetNativeArgument(args, 0);
EXPECT_VALID(arg);
Dart_SetReturnValue(args, Dart_NewInteger(1));
Dart_ExitScope();
}
static void NativeFoo2(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t i = Dart_GetNativeArgumentCount(args);
EXPECT_EQ(2, i);
Dart_Handle arg = Dart_GetNativeArgument(args, 1);
Dart_SetReturnValue(args, Dart_NewInteger(GetValue(arg)));
Dart_ExitScope();
}
static void NativeFoo3(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t i = Dart_GetNativeArgumentCount(args);
EXPECT_EQ(3, i);
Dart_Handle arg1 = Dart_GetNativeArgument(args, 1);
Dart_Handle arg2 = Dart_GetNativeArgument(args, 2);
Dart_SetReturnValue(args, Dart_NewInteger(GetValue(arg1) + GetValue(arg2)));
Dart_ExitScope();
}
static void NativeFoo4(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t i = Dart_GetNativeArgumentCount(args);
EXPECT_EQ(4, i);
Dart_Handle arg1 = Dart_GetNativeArgument(args, 1);
Dart_Handle arg2 = Dart_GetNativeArgument(args, 2);
Dart_Handle arg3 = Dart_GetNativeArgument(args, 3);
Dart_SetReturnValue(args, Dart_NewInteger(GetValue(arg1) +
GetValue(arg2) +
GetValue(arg3)));
Dart_ExitScope();
}
static Dart_NativeFunction MyNativeClosureResolver(Dart_Handle name,
int arg_count) {
const Object& obj = Object::Handle(Api::UnwrapHandle(name));
if (!obj.IsString()) {
return NULL;
}
const char* function_name = obj.ToCString();
const char* kNativeFoo1 = "NativeFoo1";
const char* kNativeFoo2 = "NativeFoo2";
const char* kNativeFoo3 = "NativeFoo3";
const char* kNativeFoo4 = "NativeFoo4";
if (!strncmp(function_name, kNativeFoo1, strlen(kNativeFoo1))) {
return &NativeFoo1;
} else if (!strncmp(function_name, kNativeFoo2, strlen(kNativeFoo2))) {
return &NativeFoo2;
} else if (!strncmp(function_name, kNativeFoo3, strlen(kNativeFoo3))) {
return &NativeFoo3;
} else if (!strncmp(function_name, kNativeFoo4, strlen(kNativeFoo4))) {
return &NativeFoo4;
} else {
UNREACHABLE();
return NULL;
}
}
TEST_CASE(NativeFunctionClosure) {
const char* kScriptChars =
"class Test {"
" int foo1() native \"NativeFoo1\";\n"
" int foo2(int i) native \"NativeFoo2\";\n"
" int foo3([int k = 10000, int l = 1]) native \"NativeFoo3\";\n"
" int foo4(int i,"
" [int j = 10, int k = 1]) native \"NativeFoo4\";\n"
" int bar1() { var func = foo1; return func(); }\n"
" int bar2(int i) { var func = foo2; return func(i); }\n"
" int bar30() { var func = foo3; return func(); }\n"
" int bar31(int i) { var func = foo3; return func(i); }\n"
" int bar32(int i, int j) { var func = foo3; return func(i, j); }\n"
" int bar41(int i) {\n"
" var func = foo4; return func(i); }\n"
" int bar42(int i, int j) {\n"
" var func = foo4; return func(i, j); }\n"
" int bar43(int i, int j, int k) {\n"
" var func = foo4; return func(i, j, k); }\n"
"}\n"
"int testMain() {\n"
" Test obj = new Test();\n"
" Expect.equals(1, obj.foo1());\n"
" Expect.equals(1, obj.bar1());\n"
"\n"
" Expect.equals(10, obj.foo2(10));\n"
" Expect.equals(10, obj.bar2(10));\n"
"\n"
" Expect.equals(10001, obj.foo3());\n"
" Expect.equals(10001, obj.bar30());\n"
" Expect.equals(2, obj.foo3(1));\n"
" Expect.equals(2, obj.bar31(1));\n"
" Expect.equals(4, obj.foo3(2, 2));\n"
" Expect.equals(4, obj.bar32(2, 2));\n"
"\n"
" Expect.equals(12, obj.foo4(1));\n"
" Expect.equals(12, obj.bar41(1));\n"
" Expect.equals(3, obj.foo4(1, 1));\n"
" Expect.equals(3, obj.bar42(1, 1));\n"
" Expect.equals(6, obj.foo4(2, 2, 2));\n"
" Expect.equals(6, obj.bar43(2, 2, 2));\n"
"\n"
" return 0;\n"
"}\n";
Dart_Handle result;
// Load a test script.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
Dart_Handle lib = Dart_LoadScript(url, source);
EXPECT_VALID(lib);
EXPECT(Dart_IsLibrary(lib));
result = Dart_SetNativeResolver(lib, &MyNativeClosureResolver);
EXPECT_VALID(result);
result = Dart_Invoke(lib, Dart_NewString("testMain"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t value = 0;
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(0, value);
}
static void StaticNativeFoo1(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t i = Dart_GetNativeArgumentCount(args);
EXPECT_EQ(0, i);
Dart_SetReturnValue(args, Dart_NewInteger(0));
Dart_ExitScope();
}
static void StaticNativeFoo2(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t i = Dart_GetNativeArgumentCount(args);
EXPECT_EQ(1, i);
Dart_Handle arg = Dart_GetNativeArgument(args, 0);
Dart_SetReturnValue(args, Dart_NewInteger(GetValue(arg)));
Dart_ExitScope();
}
static void StaticNativeFoo3(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t i = Dart_GetNativeArgumentCount(args);
EXPECT_EQ(2, i);
Dart_Handle arg1 = Dart_GetNativeArgument(args, 0);
Dart_Handle arg2 = Dart_GetNativeArgument(args, 1);
Dart_SetReturnValue(args, Dart_NewInteger(GetValue(arg1) + GetValue(arg2)));
Dart_ExitScope();
}
static void StaticNativeFoo4(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t i = Dart_GetNativeArgumentCount(args);
EXPECT_EQ(3, i);
Dart_Handle arg1 = Dart_GetNativeArgument(args, 0);
Dart_Handle arg2 = Dart_GetNativeArgument(args, 1);
Dart_Handle arg3 = Dart_GetNativeArgument(args, 2);
Dart_SetReturnValue(args, Dart_NewInteger(GetValue(arg1) +
GetValue(arg2) +
GetValue(arg3)));
Dart_ExitScope();
}
static Dart_NativeFunction MyStaticNativeClosureResolver(Dart_Handle name,
int arg_count) {
const Object& obj = Object::Handle(Api::UnwrapHandle(name));
if (!obj.IsString()) {
return NULL;
}
const char* function_name = obj.ToCString();
const char* kNativeFoo1 = "StaticNativeFoo1";
const char* kNativeFoo2 = "StaticNativeFoo2";
const char* kNativeFoo3 = "StaticNativeFoo3";
const char* kNativeFoo4 = "StaticNativeFoo4";
if (!strncmp(function_name, kNativeFoo1, strlen(kNativeFoo1))) {
return &StaticNativeFoo1;
} else if (!strncmp(function_name, kNativeFoo2, strlen(kNativeFoo2))) {
return &StaticNativeFoo2;
} else if (!strncmp(function_name, kNativeFoo3, strlen(kNativeFoo3))) {
return &StaticNativeFoo3;
} else if (!strncmp(function_name, kNativeFoo4, strlen(kNativeFoo4))) {
return &StaticNativeFoo4;
} else {
UNREACHABLE();
return NULL;
}
}
TEST_CASE(NativeStaticFunctionClosure) {
const char* kScriptChars =
"class Test {"
" static int foo1() native \"StaticNativeFoo1\";\n"
" static int foo2(int i) native \"StaticNativeFoo2\";\n"
" static int foo3([int k = 10000, int l = 1])"
" native \"StaticNativeFoo3\";\n"
" static int foo4(int i, [int j = 10, int k = 1])"
" native \"StaticNativeFoo4\";\n"
" int bar1() { var func = foo1; return func(); }\n"
" int bar2(int i) { var func = foo2; return func(i); }\n"
" int bar30() { var func = foo3; return func(); }\n"
" int bar31(int i) { var func = foo3; return func(i); }\n"
" int bar32(int i, int j) { var func = foo3; return func(i, j); }\n"
" int bar41(int i) {\n"
" var func = foo4; return func(i); }\n"
" int bar42(int i, int j) {\n"
" var func = foo4; return func(i, j); }\n"
" int bar43(int i, int j, int k) {\n"
" var func = foo4; return func(i, j, k); }\n"
"}\n"
"int testMain() {\n"
" Test obj = new Test();\n"
" Expect.equals(0, Test.foo1());\n"
" Expect.equals(0, obj.bar1());\n"
"\n"
" Expect.equals(10, Test.foo2(10));\n"
" Expect.equals(10, obj.bar2(10));\n"
"\n"
" Expect.equals(10001, Test.foo3());\n"
" Expect.equals(10001, obj.bar30());\n"
" Expect.equals(2, Test.foo3(1));\n"
" Expect.equals(2, obj.bar31(1));\n"
" Expect.equals(4, Test.foo3(2, 2));\n"
" Expect.equals(4, obj.bar32(2, 2));\n"
"\n"
" Expect.equals(12, Test.foo4(1));\n"
" Expect.equals(12, obj.bar41(1));\n"
" Expect.equals(3, Test.foo4(1, 1));\n"
" Expect.equals(3, obj.bar42(1, 1));\n"
" Expect.equals(6, Test.foo4(2, 2, 2));\n"
" Expect.equals(6, obj.bar43(2, 2, 2));\n"
"\n"
" return 0;\n"
"}\n";
Dart_Handle result;
// Load a test script.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
result = Dart_SetLibraryTagHandler(library_handler);
EXPECT_VALID(result);
Dart_Handle lib = Dart_LoadScript(url, source);
EXPECT_VALID(lib);
EXPECT(Dart_IsLibrary(lib));
result = Dart_SetNativeResolver(lib, &MyStaticNativeClosureResolver);
EXPECT_VALID(result);
result = Dart_Invoke(lib, Dart_NewString("testMain"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t value = 0;
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(0, value);
}
TEST_CASE(RangeLimits) {
uint8_t chars8[1] = {'a'};
uint16_t chars16[1] = {'a'};
uint32_t chars32[1] = {'a'};
EXPECT_ERROR(Dart_NewList(-1),
"expects argument 'length' to be in the range");
EXPECT_ERROR(Dart_NewList(Array::kMaxElements+1),
"expects argument 'length' to be in the range");
EXPECT_ERROR(Dart_NewString8(chars8, -1),
"expects argument 'length' to be in the range");
EXPECT_ERROR(Dart_NewString8(chars8, OneByteString::kMaxElements+1),
"expects argument 'length' to be in the range");
EXPECT_ERROR(Dart_NewString16(chars16, -1),
"expects argument 'length' to be in the range");
EXPECT_ERROR(Dart_NewString16(chars16, TwoByteString::kMaxElements+1),
"expects argument 'length' to be in the range");
EXPECT_ERROR(Dart_NewString32(chars32, -1),
"expects argument 'length' to be in the range");
EXPECT_ERROR(Dart_NewString32(chars32, FourByteString::kMaxElements+1),
"expects argument 'length' to be in the range");
}
TEST_CASE(NewString_Null) {
Dart_Handle str = Dart_NewString8(NULL, 0);
EXPECT_VALID(str);
EXPECT(Dart_IsString(str));
intptr_t len = -1;
EXPECT_VALID(Dart_StringLength(str, &len));
EXPECT_EQ(0, len);
str = Dart_NewString16(NULL, 0);
EXPECT_VALID(str);
EXPECT(Dart_IsString(str));
len = -1;
EXPECT_VALID(Dart_StringLength(str, &len));
EXPECT_EQ(0, len);
str = Dart_NewString32(NULL, 0);
EXPECT_VALID(str);
EXPECT(Dart_IsString(str));
len = -1;
EXPECT_VALID(Dart_StringLength(str, &len));
EXPECT_EQ(0, len);
}
// Try to allocate a peer with a handles to objects of prohibited
// subtypes.
TEST_CASE(InvalidGetSetPeer) {
void* out = &out;
EXPECT(Dart_IsError(Dart_GetPeer(Dart_Null(), &out)));
EXPECT(out == &out);
EXPECT(Dart_IsError(Dart_SetPeer(Dart_Null(), &out)));
out = &out;
EXPECT(Dart_IsError(Dart_GetPeer(Dart_True(), &out)));
EXPECT(out == &out);
EXPECT(Dart_IsError(Dart_SetPeer(Dart_True(), &out)));
out = &out;
EXPECT(Dart_IsError(Dart_GetPeer(Dart_False(), &out)));
EXPECT(out == &out);
EXPECT(Dart_IsError(Dart_SetPeer(Dart_False(), &out)));
out = &out;
Dart_Handle smi = Dart_NewInteger(0);
EXPECT(Dart_IsError(Dart_GetPeer(smi, &out)));
EXPECT(out == &out);
EXPECT(Dart_IsError(Dart_SetPeer(smi, &out)));
out = &out;
Dart_Handle big = Dart_NewIntegerFromHexCString("0x10000000000000000");
EXPECT(Dart_IsError(Dart_GetPeer(big, &out)));
EXPECT(out == &out);
EXPECT(Dart_IsError(Dart_SetPeer(big, &out)));
Dart_Handle dbl = Dart_NewDouble(0.0);
EXPECT(Dart_IsError(Dart_GetPeer(dbl, &out)));
EXPECT(out == &out);
EXPECT(Dart_IsError(Dart_SetPeer(dbl, &out)));
}
// Allocates an object in new space and assigns it a peer. Removes
// the peer and checks that the count of peer objects is decremented
// by one.
TEST_CASE(OneNewSpacePeer) {
Isolate* isolate = Isolate::Current();
Dart_Handle str = Dart_NewString("a string");
EXPECT_VALID(str);
EXPECT(Dart_IsString(str));
EXPECT_EQ(0, isolate->heap()->PeerCount());
void* out = &out;
EXPECT_VALID(Dart_GetPeer(str, &out));
EXPECT(out == NULL);
int peer = 1234;
EXPECT_VALID(Dart_SetPeer(str, &peer));
EXPECT_EQ(1, isolate->heap()->PeerCount());
out = &out;
EXPECT_VALID(Dart_GetPeer(str, &out));
EXPECT(out == reinterpret_cast<void*>(&peer));
EXPECT_VALID(Dart_SetPeer(str, NULL));
out = &out;
EXPECT_VALID(Dart_GetPeer(str, &out));
EXPECT(out == NULL);
EXPECT_EQ(0, isolate->heap()->PeerCount());
}
// Allocates an object in new space and assigns it a peer. Allows the
// peer referent to be garbage collected and checks that the count of
// peer objects is decremented by one.
TEST_CASE(CollectOneNewSpacePeer) {
Isolate* isolate = Isolate::Current();
Dart_EnterScope();
{
DARTSCOPE_NOCHECKS(isolate);
Dart_Handle str = Dart_NewString("a string");
EXPECT_VALID(str);
EXPECT(Dart_IsString(str));
EXPECT_EQ(0, isolate->heap()->PeerCount());
void* out = &out;
EXPECT_VALID(Dart_GetPeer(str, &out));
EXPECT(out == NULL);
int peer = 1234;
EXPECT_VALID(Dart_SetPeer(str, &peer));
EXPECT_EQ(1, isolate->heap()->PeerCount());
out = &out;
EXPECT_VALID(Dart_GetPeer(str, &out));
EXPECT(out == reinterpret_cast<void*>(&peer));
isolate->heap()->CollectGarbage(Heap::kNew);
EXPECT_EQ(1, isolate->heap()->PeerCount());
out = &out;
EXPECT_VALID(Dart_GetPeer(str, &out));
EXPECT(out == reinterpret_cast<void*>(&peer));
}
Dart_ExitScope();
isolate->heap()->CollectGarbage(Heap::kNew);
EXPECT_EQ(0, isolate->heap()->PeerCount());
}
// Allocates two objects in new space and assigns them peers. Removes
// the peers and checks that the count of peer objects is decremented
// by two.
TEST_CASE(TwoNewSpacePeers) {
Isolate* isolate = Isolate::Current();
Dart_Handle s1 = Dart_NewString("s1");
EXPECT_VALID(s1);
EXPECT(Dart_IsString(s1));
void* o1 = &o1;
EXPECT_VALID(Dart_GetPeer(s1, &o1));
EXPECT(o1 == NULL);
EXPECT_EQ(0, isolate->heap()->PeerCount());
int p1 = 1234;
EXPECT_VALID(Dart_SetPeer(s1, &p1));
EXPECT_EQ(1, isolate->heap()->PeerCount());
EXPECT_VALID(Dart_GetPeer(s1, &o1));
EXPECT(o1 == reinterpret_cast<void*>(&p1));
Dart_Handle s2 = Dart_NewString("a string");
EXPECT_VALID(s2);
EXPECT(Dart_IsString(s2));
EXPECT_EQ(1, isolate->heap()->PeerCount());
void* o2 = &o2;
EXPECT(Dart_GetPeer(s2, &o2));
EXPECT(o2 == NULL);
int p2 = 5678;
EXPECT_VALID(Dart_SetPeer(s2, &p2));
EXPECT_EQ(2, isolate->heap()->PeerCount());
EXPECT_VALID(Dart_GetPeer(s2, &o2));
EXPECT(o2 == reinterpret_cast<void*>(&p2));
EXPECT_VALID(Dart_SetPeer(s1, NULL));
EXPECT_EQ(1, isolate->heap()->PeerCount());
EXPECT(Dart_GetPeer(s1, &o1));
EXPECT(o1 == NULL);
EXPECT_VALID(Dart_SetPeer(s2, NULL));
EXPECT_EQ(0, isolate->heap()->PeerCount());
EXPECT(Dart_GetPeer(s2, &o2));
EXPECT(o2 == NULL);
}
// Allocates two objects in new space and assigns them a peer. Allow
// the peer referents to be garbage collected and check that the count
// of peer objects is decremented by two.
TEST_CASE(CollectTwoNewSpacePeers) {
Isolate* isolate = Isolate::Current();
Dart_EnterScope();
{
DARTSCOPE_NOCHECKS(isolate);
Dart_Handle s1 = Dart_NewString("s1");
EXPECT_VALID(s1);
EXPECT(Dart_IsString(s1));
EXPECT_EQ(0, isolate->heap()->PeerCount());
void* o1 = &o1;
EXPECT(Dart_GetPeer(s1, &o1));
EXPECT(o1 == NULL);
int p1 = 1234;
EXPECT_VALID(Dart_SetPeer(s1, &p1));
EXPECT_EQ(1, isolate->heap()->PeerCount());
EXPECT_VALID(Dart_GetPeer(s1, &o1));
EXPECT(o1 == reinterpret_cast<void*>(&p1));
Dart_Handle s2 = Dart_NewString("s2");
EXPECT_VALID(s2);
EXPECT(Dart_IsString(s2));
EXPECT_EQ(1, isolate->heap()->PeerCount());
void* o2 = &o2;
EXPECT(Dart_GetPeer(s2, &o2));
EXPECT(o2 == NULL);
int p2 = 5678;
EXPECT_VALID(Dart_SetPeer(s2, &p2));
EXPECT_EQ(2, isolate->heap()->PeerCount());
EXPECT_VALID(Dart_GetPeer(s2, &o2));
EXPECT(o2 == reinterpret_cast<void*>(&p2));
}
Dart_ExitScope();
isolate->heap()->CollectGarbage(Heap::kNew);
EXPECT_EQ(0, isolate->heap()->PeerCount());
}
// Allocates several objects in new space. Performs successive
// garbage collections and checks that the peer count is stable.
TEST_CASE(CopyNewSpacePeers) {
const int kPeerCount = 10;
Isolate* isolate = Isolate::Current();
Dart_Handle s[kPeerCount];
for (int i = 0; i < kPeerCount; ++i) {
s[i] = Dart_NewString("a string");
EXPECT_VALID(s[i]);
EXPECT(Dart_IsString(s[i]));
void* o = &o;
EXPECT_VALID(Dart_GetPeer(s[i], &o));
EXPECT(o == NULL);
}
EXPECT_EQ(0, isolate->heap()->PeerCount());
int p[kPeerCount];
for (int i = 0; i < kPeerCount; ++i) {
EXPECT_VALID(Dart_SetPeer(s[i], &p[i]));
EXPECT_EQ(i + 1, isolate->heap()->PeerCount());
void* o = &o;
EXPECT_VALID(Dart_GetPeer(s[i], &o));
EXPECT(o == reinterpret_cast<void*>(&p[i]));
}
EXPECT_EQ(kPeerCount, isolate->heap()->PeerCount());
isolate->heap()->CollectGarbage(Heap::kNew);
EXPECT_EQ(kPeerCount, isolate->heap()->PeerCount());
isolate->heap()->CollectGarbage(Heap::kNew);
EXPECT_EQ(kPeerCount, isolate->heap()->PeerCount());
}
// Allocates an object in new space and assigns it a peer. Promotes
// the peer to old space. Removes the peer and check that the count
// of peer objects is decremented by one.
TEST_CASE(OnePromotedPeer) {
Isolate* isolate = Isolate::Current();
Dart_Handle str = Dart_NewString("a string");
EXPECT_VALID(str);
EXPECT(Dart_IsString(str));
EXPECT_EQ(0, isolate->heap()->PeerCount());
void* out = &out;
EXPECT(Dart_GetPeer(str, &out));
EXPECT(out == NULL);
int peer = 1234;
EXPECT_VALID(Dart_SetPeer(str, &peer));
out = &out;
EXPECT(Dart_GetPeer(str, &out));
EXPECT(out == reinterpret_cast<void*>(&peer));
EXPECT_EQ(1, isolate->heap()->PeerCount());
isolate->heap()->CollectGarbage(Heap::kNew);
isolate->heap()->CollectGarbage(Heap::kNew);
{
DARTSCOPE_NOCHECKS(isolate);
String& handle = String::Handle();
handle ^= Api::UnwrapHandle(str);
EXPECT(handle.IsOld());
}
EXPECT_VALID(Dart_GetPeer(str, &out));
EXPECT(out == reinterpret_cast<void*>(&peer));
EXPECT_EQ(1, isolate->heap()->PeerCount());
EXPECT_VALID(Dart_SetPeer(str, NULL));
out = &out;
EXPECT_VALID(Dart_GetPeer(str, &out));
EXPECT(out == NULL);
EXPECT_EQ(0, isolate->heap()->PeerCount());
}
// Allocates an object in old space and assigns it a peer. Removes
// the peer and checks that the count of peer objects is decremented
// by one.
TEST_CASE(OneOldSpacePeer) {
Isolate* isolate = Isolate::Current();
Dart_Handle str = Api::NewHandle(isolate, String::New("str", Heap::kOld));
EXPECT_VALID(str);
EXPECT(Dart_IsString(str));
EXPECT_EQ(0, isolate->heap()->PeerCount());
void* out = &out;
EXPECT(Dart_GetPeer(str, &out));
EXPECT(out == NULL);
int peer = 1234;
EXPECT_VALID(Dart_SetPeer(str, &peer));
EXPECT_EQ(1, isolate->heap()->PeerCount());
out = &out;
EXPECT_VALID(Dart_GetPeer(str, &out));
EXPECT(out == reinterpret_cast<void*>(&peer));
isolate->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(1, isolate->heap()->PeerCount());
EXPECT_VALID(Dart_GetPeer(str, &out));
EXPECT(out == reinterpret_cast<void*>(&peer));
EXPECT_VALID(Dart_SetPeer(str, NULL));
out = &out;
EXPECT_VALID(Dart_GetPeer(str, &out));
EXPECT(out == NULL);
EXPECT_EQ(0, isolate->heap()->PeerCount());
}
// Allocates an object in old space and assigns it a peer. Allow the
// peer referent to be garbage collected and check that the count of
// peer objects is decremented by one.
TEST_CASE(CollectOneOldSpacePeer) {
Isolate* isolate = Isolate::Current();
Dart_EnterScope();
{
DARTSCOPE_NOCHECKS(isolate);
Dart_Handle str = Api::NewHandle(isolate, String::New("str", Heap::kOld));
EXPECT_VALID(str);
EXPECT(Dart_IsString(str));
EXPECT_EQ(0, isolate->heap()->PeerCount());
void* out = &out;
EXPECT(Dart_GetPeer(str, &out));
EXPECT(out == NULL);
int peer = 1234;
EXPECT_VALID(Dart_SetPeer(str, &peer));
EXPECT_EQ(1, isolate->heap()->PeerCount());
out = &out;
EXPECT_VALID(Dart_GetPeer(str, &out));
EXPECT(out == reinterpret_cast<void*>(&peer));
isolate->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(1, isolate->heap()->PeerCount());
EXPECT_VALID(Dart_GetPeer(str, &out));
EXPECT(out == reinterpret_cast<void*>(&peer));
}
Dart_ExitScope();
isolate->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(0, isolate->heap()->PeerCount());
}
// Allocates two objects in old space and assigns them peers. Removes
// the peers and checks that the count of peer objects is decremented
// by two.
TEST_CASE(TwoOldSpacePeers) {
Isolate* isolate = Isolate::Current();
Dart_Handle s1 = Api::NewHandle(isolate, String::New("s1", Heap::kOld));
EXPECT_VALID(s1);
EXPECT(Dart_IsString(s1));
EXPECT_EQ(0, isolate->heap()->PeerCount());
void* o1 = &o1;
EXPECT(Dart_GetPeer(s1, &o1));
EXPECT(o1 == NULL);
int p1 = 1234;
EXPECT_VALID(Dart_SetPeer(s1, &p1));
EXPECT_EQ(1, isolate->heap()->PeerCount());
o1 = &o1;
EXPECT_VALID(Dart_GetPeer(s1, &o1));
EXPECT(o1 == reinterpret_cast<void*>(&p1));
Dart_Handle s2 = Api::NewHandle(isolate, String::New("s2", Heap::kOld));
EXPECT_VALID(s2);
EXPECT(Dart_IsString(s2));
EXPECT_EQ(1, isolate->heap()->PeerCount());
void* o2 = &o2;
EXPECT(Dart_GetPeer(s2, &o2));
EXPECT(o2 == NULL);
int p2 = 5678;
EXPECT_VALID(Dart_SetPeer(s2, &p2));
EXPECT_EQ(2, isolate->heap()->PeerCount());
o2 = &o2;
EXPECT_VALID(Dart_GetPeer(s2, &o2));
EXPECT(o2 == reinterpret_cast<void*>(&p2));
EXPECT_VALID(Dart_SetPeer(s1, NULL));
EXPECT_EQ(1, isolate->heap()->PeerCount());
o1 = &o1;
EXPECT(Dart_GetPeer(s1, &o1));
EXPECT(o1 == NULL);
EXPECT_VALID(Dart_SetPeer(s2, NULL));
EXPECT_EQ(0, isolate->heap()->PeerCount());
o2 = &o2;
EXPECT_VALID(Dart_GetPeer(s2, &o2));
EXPECT(o2 == NULL);
}
// Allocates two objects in old space and assigns them a peer. Allows
// the peer referents to be garbage collected and checks that the
// count of peer objects is decremented by two.
TEST_CASE(CollectTwoOldSpacePeers) {
Isolate* isolate = Isolate::Current();
Dart_EnterScope();
{
DARTSCOPE_NOCHECKS(isolate);
Dart_Handle s1 = Api::NewHandle(isolate, String::New("s1", Heap::kOld));
EXPECT_VALID(s1);
EXPECT(Dart_IsString(s1));
EXPECT_EQ(0, isolate->heap()->PeerCount());
void* o1 = &o1;
EXPECT(Dart_GetPeer(s1, &o1));
EXPECT(o1 == NULL);
int p1 = 1234;
EXPECT_VALID(Dart_SetPeer(s1, &p1));
EXPECT_EQ(1, isolate->heap()->PeerCount());
o1 = &o1;
EXPECT_VALID(Dart_GetPeer(s1, &o1));
EXPECT(o1 == reinterpret_cast<void*>(&p1));
Dart_Handle s2 = Api::NewHandle(isolate, String::New("s2", Heap::kOld));
EXPECT_VALID(s2);
EXPECT(Dart_IsString(s2));
EXPECT_EQ(1, isolate->heap()->PeerCount());
void* o2 = &o2;
EXPECT(Dart_GetPeer(s2, &o2));
EXPECT(o2 == NULL);
int p2 = 5678;
EXPECT_VALID(Dart_SetPeer(s2, &p2));
EXPECT_EQ(2, isolate->heap()->PeerCount());
o2 = &o2;
EXPECT_VALID(Dart_GetPeer(s2, &o2));
EXPECT(o2 == reinterpret_cast<void*>(&p2));
}
Dart_ExitScope();
isolate->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(0, isolate->heap()->PeerCount());
}
#endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64).
} // namespace dart