OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "extensions/renderer/bindings/exception_handler.h" |
| 6 |
| 7 #include <string> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/optional.h" |
| 11 #include "base/strings/stringprintf.h" |
| 12 #include "extensions/renderer/bindings/api_binding_test.h" |
| 13 #include "extensions/renderer/bindings/api_binding_test_util.h" |
| 14 #include "gin/converter.h" |
| 15 |
| 16 namespace extensions { |
| 17 |
| 18 namespace { |
| 19 |
| 20 void PopulateError(base::Optional<std::string>* error_out, |
| 21 v8::Local<v8::Context> context, |
| 22 const std::string& error) { |
| 23 *error_out = error; |
| 24 } |
| 25 |
| 26 void ThrowException(v8::Local<v8::Context> context, |
| 27 const std::string& to_throw, |
| 28 ExceptionHandler* handler) { |
| 29 v8::Isolate* isolate = context->GetIsolate(); |
| 30 v8::TryCatch try_catch(isolate); |
| 31 v8::Local<v8::Function> function = FunctionFromString( |
| 32 context, |
| 33 base::StringPrintf("(function() { throw %s; })", to_throw.c_str())); |
| 34 ignore_result(function->Call(context, v8::Undefined(isolate), 0, nullptr)); |
| 35 ASSERT_TRUE(try_catch.HasCaught()); |
| 36 handler->HandleException(context, "handled", &try_catch); |
| 37 } |
| 38 |
| 39 } // namespace |
| 40 |
| 41 using ExceptionHandlerTest = APIBindingTest; |
| 42 |
| 43 TEST_F(ExceptionHandlerTest, TestBasicHandling) { |
| 44 v8::HandleScope handle_scope(isolate()); |
| 45 v8::Local<v8::Context> context = MainContext(); |
| 46 |
| 47 base::Optional<std::string> logged_error; |
| 48 ExceptionHandler handler(base::Bind(&PopulateError, &logged_error), |
| 49 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
| 50 |
| 51 ThrowException(context, "new Error('some error')", &handler); |
| 52 |
| 53 ASSERT_TRUE(logged_error); |
| 54 EXPECT_EQ("handled: Uncaught Error: some error", *logged_error); |
| 55 } |
| 56 |
| 57 TEST_F(ExceptionHandlerTest, PerContextHandlers) { |
| 58 v8::HandleScope handle_scope(isolate()); |
| 59 v8::Local<v8::Context> context_a = MainContext(); |
| 60 v8::Local<v8::Context> context_b = AddContext(); |
| 61 |
| 62 base::Optional<std::string> logged_error; |
| 63 ExceptionHandler handler(base::Bind(&PopulateError, &logged_error), |
| 64 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
| 65 |
| 66 v8::Local<v8::Function> custom_handler = FunctionFromString( |
| 67 context_a, |
| 68 "(function(message, exception) {\n" |
| 69 " this.loggedMessage = message;\n" |
| 70 " this.loggedExceptionMessage = exception && exception.message;\n" |
| 71 "})"); |
| 72 |
| 73 handler.SetHandlerForContext(context_a, custom_handler); |
| 74 ThrowException(context_a, "new Error('context a error')", &handler); |
| 75 EXPECT_FALSE(logged_error); |
| 76 EXPECT_EQ("\"handled: Uncaught Error: context a error\"", |
| 77 GetStringPropertyFromObject(context_a->Global(), context_a, |
| 78 "loggedMessage")); |
| 79 EXPECT_EQ("\"context a error\"", |
| 80 GetStringPropertyFromObject(context_a->Global(), context_a, |
| 81 "loggedExceptionMessage")); |
| 82 |
| 83 ASSERT_TRUE(context_a->Global() |
| 84 ->Set(context_a, |
| 85 gin::StringToSymbol(isolate(), "loggedMessage"), |
| 86 v8::Undefined(isolate())) |
| 87 .ToChecked()); |
| 88 ASSERT_TRUE( |
| 89 context_a->Global() |
| 90 ->Set(context_a, |
| 91 gin::StringToSymbol(isolate(), "loggedExceptionMessage"), |
| 92 v8::Undefined(isolate())) |
| 93 .ToChecked()); |
| 94 |
| 95 ThrowException(context_b, "new Error('context b error')", &handler); |
| 96 ASSERT_TRUE(logged_error); |
| 97 EXPECT_EQ("handled: Uncaught Error: context b error", *logged_error); |
| 98 EXPECT_EQ("undefined", GetStringPropertyFromObject( |
| 99 context_a->Global(), context_a, "loggedMessage")); |
| 100 EXPECT_EQ("undefined", |
| 101 GetStringPropertyFromObject(context_a->Global(), context_a, |
| 102 "loggedExceptionMessage")); |
| 103 } |
| 104 |
| 105 TEST_F(ExceptionHandlerTest, ThrowingNonErrors) { |
| 106 v8::HandleScope handle_scope(isolate()); |
| 107 v8::Local<v8::Context> context = MainContext(); |
| 108 |
| 109 base::Optional<std::string> logged_error; |
| 110 ExceptionHandler handler(base::Bind(&PopulateError, &logged_error), |
| 111 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
| 112 |
| 113 ThrowException(context, "'hello'", &handler); |
| 114 ASSERT_TRUE(logged_error); |
| 115 EXPECT_EQ("handled: Uncaught hello", *logged_error); |
| 116 logged_error.reset(); |
| 117 |
| 118 ThrowException(context, "{ message: 'hello' }", &handler); |
| 119 ASSERT_TRUE(logged_error); |
| 120 EXPECT_EQ("handled: Uncaught #<Object>", *logged_error); |
| 121 logged_error.reset(); |
| 122 |
| 123 ThrowException(context, "{ toString: function() { throw 'goodbye' } }", |
| 124 &handler); |
| 125 ASSERT_TRUE(logged_error); |
| 126 EXPECT_EQ("handled: Uncaught [object Object]", *logged_error); |
| 127 |
| 128 v8::Local<v8::Function> custom_handler = |
| 129 FunctionFromString(context, |
| 130 "(function(message, exception) {\n" |
| 131 " this.loggedMessage = message;\n" |
| 132 " this.loggedException = exception;\n" |
| 133 "})"); |
| 134 |
| 135 handler.SetHandlerForContext(context, custom_handler); |
| 136 ThrowException(context, "'hello'", &handler); |
| 137 EXPECT_EQ( |
| 138 "\"handled: Uncaught hello\"", |
| 139 GetStringPropertyFromObject(context->Global(), context, "loggedMessage")); |
| 140 EXPECT_EQ("\"hello\"", GetStringPropertyFromObject(context->Global(), context, |
| 141 "loggedException")); |
| 142 } |
| 143 |
| 144 } // namespace extensions |
OLD | NEW |