| Index: test/cctest/test-api.cc
|
| diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
|
| index 35a7156e9e509ec11df1ab63a5d5e3ac4a2fa7f8..135a13378ab28c82504bacc959ff54892ac46c50 100644
|
| --- a/test/cctest/test-api.cc
|
| +++ b/test/cctest/test-api.cc
|
| @@ -2021,6 +2021,21 @@ void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
|
| SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
|
| }
|
|
|
| +void SymbolAccessorGetterReturnsDefault(Local<Name> name,
|
| + const v8::PropertyCallbackInfo<v8::Value>& info) {
|
| + CHECK(name->IsSymbol());
|
| + Local<Symbol> sym = Local<Symbol>::Cast(name);
|
| + if (sym->Name()->IsUndefined())
|
| + return;
|
| + info.GetReturnValue().Set(info.Data());
|
| +}
|
| +
|
| +static void ThrowingSymbolAccessorGetter(
|
| + Local<Name> name,
|
| + const v8::PropertyCallbackInfo<v8::Value>& info) {
|
| + info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
|
| +}
|
| +
|
| void EmptyInterceptorGetter(Local<String> name,
|
| const v8::PropertyCallbackInfo<v8::Value>& info) {
|
| }
|
| @@ -13492,6 +13507,115 @@ THREADED_TEST(ObjectProtoToString) {
|
| }
|
|
|
|
|
| +TEST(ObjectProtoToStringES6) {
|
| + // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
|
| + i::FLAG_harmony_tostring = true;
|
| + LocalContext context;
|
| + v8::Isolate* isolate = CcTest::isolate();
|
| + v8::HandleScope scope(isolate);
|
| + Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
|
| + templ->SetClassName(v8_str("MyClass"));
|
| +
|
| + Local<String> customized_tostring = v8_str("customized toString");
|
| +
|
| + // Replace Object.prototype.toString
|
| + CompileRun("Object.prototype.toString = function() {"
|
| + " return 'customized toString';"
|
| + "}");
|
| +
|
| + // Normal ToString call should call replaced Object.prototype.toString
|
| + Local<v8::Object> instance = templ->GetFunction()->NewInstance();
|
| + Local<String> value = instance->ToString();
|
| + CHECK(value->IsString() && value->Equals(customized_tostring));
|
| +
|
| + // ObjectProtoToString should not call replace toString function.
|
| + value = instance->ObjectProtoToString();
|
| + CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
|
| +
|
| + // Check global
|
| + value = context->Global()->ObjectProtoToString();
|
| + CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
|
| +
|
| + // Check ordinary object
|
| + Local<Value> object = CompileRun("new Object()");
|
| + value = object.As<v8::Object>()->ObjectProtoToString();
|
| + CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
|
| +
|
| + // Check that ES6 semantics using @@toStringTag work
|
| + Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
|
| +
|
| +#define TEST_TOSTRINGTAG(type, tag, expected) \
|
| + do { \
|
| + object = CompileRun("new " #type "()"); \
|
| + object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
|
| + value = object.As<v8::Object>()->ObjectProtoToString(); \
|
| + CHECK(value->IsString() && value->Equals( \
|
| + v8_str("[object " #expected "]"))); \
|
| + } while (0)
|
| +
|
| + TEST_TOSTRINGTAG(Array, Object, Object);
|
| + TEST_TOSTRINGTAG(Object, Arguments, ~Arguments);
|
| + TEST_TOSTRINGTAG(Object, Array, ~Array);
|
| + TEST_TOSTRINGTAG(Object, Boolean, ~Boolean);
|
| + TEST_TOSTRINGTAG(Object, Date, ~Date);
|
| + TEST_TOSTRINGTAG(Object, Error, ~Error);
|
| + TEST_TOSTRINGTAG(Object, Function, ~Function);
|
| + TEST_TOSTRINGTAG(Object, Number, ~Number);
|
| + TEST_TOSTRINGTAG(Object, RegExp, ~RegExp);
|
| + TEST_TOSTRINGTAG(Object, String, ~String);
|
| + TEST_TOSTRINGTAG(Object, Foo, Foo);
|
| +
|
| +#undef TEST_TOSTRINGTAG
|
| +
|
| + // @@toStringTag getter throws
|
| + Local<Value> obj = v8::Object::New(isolate);
|
| + obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
|
| + { TryCatch try_catch;
|
| + value = obj.As<v8::Object>()->ObjectProtoToString();
|
| + CHECK(value.IsEmpty());
|
| + CHECK(try_catch.HasCaught());
|
| + }
|
| +
|
| + // @@toStringTag getter does not throw
|
| + obj = v8::Object::New(isolate);
|
| + obj.As<v8::Object>()->SetAccessor(toStringTag,
|
| + SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
|
| + { TryCatch try_catch;
|
| + value = obj.As<v8::Object>()->ObjectProtoToString();
|
| + CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
|
| + CHECK(!try_catch.HasCaught());
|
| + }
|
| +
|
| + // JS @@toStringTag value
|
| + obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
|
| + { TryCatch try_catch;
|
| + value = obj.As<v8::Object>()->ObjectProtoToString();
|
| + CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
|
| + CHECK(!try_catch.HasCaught());
|
| + }
|
| +
|
| + // JS @@toStringTag getter throws
|
| + obj = CompileRun("obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
|
| + " get: function() { throw 'Test'; }"
|
| + "}); obj");
|
| + { TryCatch try_catch;
|
| + value = obj.As<v8::Object>()->ObjectProtoToString();
|
| + CHECK(value.IsEmpty());
|
| + CHECK(try_catch.HasCaught());
|
| + }
|
| +
|
| + // JS @@toStringTag getter does not throw
|
| + obj = CompileRun("obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
|
| + " get: function() { return 'Test'; }"
|
| + "}); obj");
|
| + { TryCatch try_catch;
|
| + value = obj.As<v8::Object>()->ObjectProtoToString();
|
| + CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
|
| + CHECK(!try_catch.HasCaught());
|
| + }
|
| +}
|
| +
|
| +
|
| THREADED_TEST(ObjectGetConstructorName) {
|
| LocalContext context;
|
| v8::HandleScope scope(context->GetIsolate());
|
|
|