| Index: extensions/renderer/bindings/exception_handler_unittest.cc
|
| diff --git a/extensions/renderer/bindings/exception_handler_unittest.cc b/extensions/renderer/bindings/exception_handler_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e79b351d1387b0f490d3f582e41ebc756d501765
|
| --- /dev/null
|
| +++ b/extensions/renderer/bindings/exception_handler_unittest.cc
|
| @@ -0,0 +1,144 @@
|
| +// 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 "extensions/renderer/bindings/exception_handler.h"
|
| +
|
| +#include <string>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/optional.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "extensions/renderer/bindings/api_binding_test.h"
|
| +#include "extensions/renderer/bindings/api_binding_test_util.h"
|
| +#include "gin/converter.h"
|
| +
|
| +namespace extensions {
|
| +
|
| +namespace {
|
| +
|
| +void PopulateError(base::Optional<std::string>* error_out,
|
| + v8::Local<v8::Context> context,
|
| + const std::string& error) {
|
| + *error_out = error;
|
| +}
|
| +
|
| +void ThrowException(v8::Local<v8::Context> context,
|
| + const std::string& to_throw,
|
| + ExceptionHandler* handler) {
|
| + v8::Isolate* isolate = context->GetIsolate();
|
| + v8::TryCatch try_catch(isolate);
|
| + v8::Local<v8::Function> function = FunctionFromString(
|
| + context,
|
| + base::StringPrintf("(function() { throw %s; })", to_throw.c_str()));
|
| + ignore_result(function->Call(context, v8::Undefined(isolate), 0, nullptr));
|
| + ASSERT_TRUE(try_catch.HasCaught());
|
| + handler->HandleException(context, "handled", &try_catch);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +using ExceptionHandlerTest = APIBindingTest;
|
| +
|
| +TEST_F(ExceptionHandlerTest, TestBasicHandling) {
|
| + v8::HandleScope handle_scope(isolate());
|
| + v8::Local<v8::Context> context = MainContext();
|
| +
|
| + base::Optional<std::string> logged_error;
|
| + ExceptionHandler handler(base::Bind(&PopulateError, &logged_error),
|
| + base::Bind(&RunFunctionOnGlobalAndIgnoreResult));
|
| +
|
| + ThrowException(context, "new Error('some error')", &handler);
|
| +
|
| + ASSERT_TRUE(logged_error);
|
| + EXPECT_EQ("handled: Uncaught Error: some error", *logged_error);
|
| +}
|
| +
|
| +TEST_F(ExceptionHandlerTest, PerContextHandlers) {
|
| + v8::HandleScope handle_scope(isolate());
|
| + v8::Local<v8::Context> context_a = MainContext();
|
| + v8::Local<v8::Context> context_b = AddContext();
|
| +
|
| + base::Optional<std::string> logged_error;
|
| + ExceptionHandler handler(base::Bind(&PopulateError, &logged_error),
|
| + base::Bind(&RunFunctionOnGlobalAndIgnoreResult));
|
| +
|
| + v8::Local<v8::Function> custom_handler = FunctionFromString(
|
| + context_a,
|
| + "(function(message, exception) {\n"
|
| + " this.loggedMessage = message;\n"
|
| + " this.loggedExceptionMessage = exception && exception.message;\n"
|
| + "})");
|
| +
|
| + handler.SetHandlerForContext(context_a, custom_handler);
|
| + ThrowException(context_a, "new Error('context a error')", &handler);
|
| + EXPECT_FALSE(logged_error);
|
| + EXPECT_EQ("\"handled: Uncaught Error: context a error\"",
|
| + GetStringPropertyFromObject(context_a->Global(), context_a,
|
| + "loggedMessage"));
|
| + EXPECT_EQ("\"context a error\"",
|
| + GetStringPropertyFromObject(context_a->Global(), context_a,
|
| + "loggedExceptionMessage"));
|
| +
|
| + ASSERT_TRUE(context_a->Global()
|
| + ->Set(context_a,
|
| + gin::StringToSymbol(isolate(), "loggedMessage"),
|
| + v8::Undefined(isolate()))
|
| + .ToChecked());
|
| + ASSERT_TRUE(
|
| + context_a->Global()
|
| + ->Set(context_a,
|
| + gin::StringToSymbol(isolate(), "loggedExceptionMessage"),
|
| + v8::Undefined(isolate()))
|
| + .ToChecked());
|
| +
|
| + ThrowException(context_b, "new Error('context b error')", &handler);
|
| + ASSERT_TRUE(logged_error);
|
| + EXPECT_EQ("handled: Uncaught Error: context b error", *logged_error);
|
| + EXPECT_EQ("undefined", GetStringPropertyFromObject(
|
| + context_a->Global(), context_a, "loggedMessage"));
|
| + EXPECT_EQ("undefined",
|
| + GetStringPropertyFromObject(context_a->Global(), context_a,
|
| + "loggedExceptionMessage"));
|
| +}
|
| +
|
| +TEST_F(ExceptionHandlerTest, ThrowingNonErrors) {
|
| + v8::HandleScope handle_scope(isolate());
|
| + v8::Local<v8::Context> context = MainContext();
|
| +
|
| + base::Optional<std::string> logged_error;
|
| + ExceptionHandler handler(base::Bind(&PopulateError, &logged_error),
|
| + base::Bind(&RunFunctionOnGlobalAndIgnoreResult));
|
| +
|
| + ThrowException(context, "'hello'", &handler);
|
| + ASSERT_TRUE(logged_error);
|
| + EXPECT_EQ("handled: Uncaught hello", *logged_error);
|
| + logged_error.reset();
|
| +
|
| + ThrowException(context, "{ message: 'hello' }", &handler);
|
| + ASSERT_TRUE(logged_error);
|
| + EXPECT_EQ("handled: Uncaught #<Object>", *logged_error);
|
| + logged_error.reset();
|
| +
|
| + ThrowException(context, "{ toString: function() { throw 'goodbye' } }",
|
| + &handler);
|
| + ASSERT_TRUE(logged_error);
|
| + EXPECT_EQ("handled: Uncaught [object Object]", *logged_error);
|
| +
|
| + v8::Local<v8::Function> custom_handler =
|
| + FunctionFromString(context,
|
| + "(function(message, exception) {\n"
|
| + " this.loggedMessage = message;\n"
|
| + " this.loggedException = exception;\n"
|
| + "})");
|
| +
|
| + handler.SetHandlerForContext(context, custom_handler);
|
| + ThrowException(context, "'hello'", &handler);
|
| + EXPECT_EQ(
|
| + "\"handled: Uncaught hello\"",
|
| + GetStringPropertyFromObject(context->Global(), context, "loggedMessage"));
|
| + EXPECT_EQ("\"hello\"", GetStringPropertyFromObject(context->Global(), context,
|
| + "loggedException"));
|
| +}
|
| +
|
| +} // namespace extensions
|
|
|