blob: 889f361d37bab9efa846877ec3982cb5a12d90e7 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/bindings/core/v8/dictionary.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "v8/include/v8.h"
namespace blink {
namespace {
class V8DictionaryTest : public testing::Test {
protected:
static Dictionary CreateDictionary(ScriptState* script_state, const char* s) {
v8::Local<v8::String> source =
v8::String::NewFromUtf8(script_state->GetIsolate(), s,
v8::NewStringType::kNormal)
.ToLocalChecked();
v8::Local<v8::Script> script =
v8::Script::Compile(script_state->GetContext(), source)
.ToLocalChecked();
v8::Local<v8::Value> value =
script->Run(script_state->GetContext()).ToLocalChecked();
DCHECK(!value.IsEmpty());
DCHECK(value->IsObject());
NonThrowableExceptionState exception_state;
Dictionary dictionary(script_state->GetIsolate(), value, exception_state);
return dictionary;
}
};
TEST_F(V8DictionaryTest, Get_Empty) {
V8TestingScope scope;
Dictionary dictionary = CreateDictionary(scope.GetScriptState(), "({})");
auto r = dictionary.Get<IDLByteString>("key", scope.GetExceptionState());
ASSERT_FALSE(scope.GetExceptionState().HadException());
EXPECT_FALSE(r.has_value());
}
TEST_F(V8DictionaryTest, Get_NonPresentForNonEmpty) {
V8TestingScope scope;
Dictionary dictionary =
CreateDictionary(scope.GetScriptState(), "({foo: 3})");
auto r = dictionary.Get<IDLByteString>("key", scope.GetExceptionState());
ASSERT_FALSE(scope.GetExceptionState().HadException());
EXPECT_FALSE(r.has_value());
}
TEST_F(V8DictionaryTest, Get_UndefinedValue) {
V8TestingScope scope;
Dictionary dictionary =
CreateDictionary(scope.GetScriptState(), "({foo: undefined})");
auto r = dictionary.Get<IDLByteString>("foo", scope.GetExceptionState());
ASSERT_FALSE(scope.GetExceptionState().HadException());
EXPECT_FALSE(r.has_value());
}
TEST_F(V8DictionaryTest, Get_Found) {
V8TestingScope scope;
Dictionary dictionary =
CreateDictionary(scope.GetScriptState(), "({foo: 3})");
auto r = dictionary.Get<IDLByteString>("foo", scope.GetExceptionState());
ASSERT_FALSE(scope.GetExceptionState().HadException());
ASSERT_TRUE(r.has_value());
EXPECT_EQ(*r, "3");
}
TEST_F(V8DictionaryTest, Get_Found2) {
V8TestingScope scope;
Dictionary dictionary =
CreateDictionary(scope.GetScriptState(), "({foo: '3'})");
auto r = dictionary.Get<IDLLong>("foo", scope.GetExceptionState());
ASSERT_FALSE(scope.GetExceptionState().HadException());
ASSERT_TRUE(r.has_value());
EXPECT_EQ(*r, 3);
}
TEST_F(V8DictionaryTest, Get_Getter) {
V8TestingScope scope;
Dictionary dictionary = CreateDictionary(scope.GetScriptState(),
"({get foo() { return 'xy'; }})");
auto r = dictionary.Get<IDLByteString>("foo", scope.GetExceptionState());
ASSERT_FALSE(scope.GetExceptionState().HadException());
ASSERT_TRUE(r.has_value());
EXPECT_EQ(*r, "xy");
}
TEST_F(V8DictionaryTest, Get_ExceptionOnAccess) {
V8TestingScope scope;
Dictionary dictionary = CreateDictionary(scope.GetScriptState(),
"({get foo() { throw Error(2); }})");
auto r = dictionary.Get<IDLByteString>("foo", scope.GetExceptionState());
ASSERT_TRUE(scope.GetExceptionState().HadException());
ASSERT_FALSE(r.has_value());
}
// TODO(bashi,yukishiino): Should rethrow the exception.
// http://crbug.com/666661
TEST_F(V8DictionaryTest, Get_ExceptionOnAccess2) {
V8TestingScope scope;
Dictionary dictionary = CreateDictionary(scope.GetScriptState(),
"({get foo() { throw Error(2); }})");
v8::Local<v8::Value> value;
v8::TryCatch try_catch(scope.GetIsolate());
ASSERT_FALSE(dictionary.Get("foo", value));
ASSERT_FALSE(try_catch.HasCaught());
}
// TODO(bashi,yukishiino): Should rethrow the exception.
// http://crbug.com/666661
TEST_F(V8DictionaryTest, Get_InvalidInnerDictionary) {
V8TestingScope scope;
Dictionary dictionary =
CreateDictionary(scope.GetScriptState(), "({foo: 4})");
v8::TryCatch try_catch(scope.GetIsolate());
Dictionary inner_dictionary;
ASSERT_TRUE(dictionary.Get("foo", inner_dictionary));
ASSERT_FALSE(try_catch.HasCaught());
EXPECT_TRUE(inner_dictionary.IsUndefinedOrNull());
}
TEST_F(V8DictionaryTest, Get_TypeConversion) {
V8TestingScope scope;
Dictionary dictionary = CreateDictionary(
scope.GetScriptState(), "({foo: { toString() { return 'hello'; } } })");
auto r = dictionary.Get<IDLByteString>("foo", scope.GetExceptionState());
ASSERT_FALSE(scope.GetExceptionState().HadException());
ASSERT_TRUE(r.has_value());
EXPECT_EQ(*r, "hello");
}
TEST_F(V8DictionaryTest, Get_ConversionError) {
V8TestingScope scope;
Dictionary dictionary = CreateDictionary(
scope.GetScriptState(),
"({get foo() { return { toString() { throw Error(88); } };} })");
auto r = dictionary.Get<IDLByteString>("foo", scope.GetExceptionState());
ASSERT_TRUE(scope.GetExceptionState().HadException());
ASSERT_FALSE(r.has_value());
}
TEST_F(V8DictionaryTest, Get_ConversionError2) {
V8TestingScope scope;
Dictionary dictionary =
CreateDictionary(scope.GetScriptState(), "({foo: NaN})");
auto r = dictionary.Get<IDLDouble>("foo", scope.GetExceptionState());
ASSERT_TRUE(scope.GetExceptionState().HadException());
ASSERT_FALSE(r.has_value());
}
} // namespace
} // namespace blink