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..cc0a4ecfd994ebe68e0de51329bd8ca88a81213a |
--- /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 |