Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: extensions/renderer/api_last_error_unittest.cc

Issue 2657613005: [Extensions Bindings] Add chrome.runtime.lastError support (Closed)
Patch Set: . Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « extensions/renderer/api_last_error.cc ('k') | extensions/renderer/api_request_handler.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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/api_last_error.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "extensions/renderer/api_binding_test.h"
10 #include "extensions/renderer/api_binding_test_util.h"
11 #include "gin/converter.h"
12 #include "gin/public/context_holder.h"
13
14 namespace extensions {
15
16 namespace {
17
18 std::string GetLastError(v8::Local<v8::Object> parent,
19 v8::Local<v8::Context> context) {
20 v8::Local<v8::Value> last_error =
21 GetPropertyFromObject(parent, context, "lastError");
22 if (last_error.IsEmpty() || !last_error->IsObject())
23 return V8ToString(last_error, context);
24 v8::Local<v8::Value> message =
25 GetPropertyFromObject(last_error.As<v8::Object>(), context, "message");
26 return V8ToString(message, context);
27 }
28
29 using ParentList =
30 std::vector<std::pair<v8::Local<v8::Context>, v8::Local<v8::Object>>>;
31 v8::Local<v8::Object> GetParent(const ParentList& parents,
32 v8::Local<v8::Context> context) {
33 // This would be simpler with a map<context, object>, but Local<> doesn't
34 // define an operator<.
35 for (const auto& parent : parents) {
36 if (parent.first == context)
37 return parent.second;
38 }
39 return v8::Local<v8::Object>();
40 }
41
42 } // namespace
43
44 using APILastErrorTest = APIBindingTest;
45
46 // Test basic functionality of the lastError object.
47 TEST_F(APILastErrorTest, TestLastError) {
48 v8::HandleScope handle_scope(isolate());
49 v8::Local<v8::Context> context = ContextLocal();
50 v8::Local<v8::Object> parent_object = v8::Object::New(isolate());
51
52 ParentList parents = {{context, parent_object}};
53 APILastError last_error(base::Bind(&GetParent, parents));
54
55 EXPECT_EQ("undefined", GetLastError(parent_object, context));
56 // Check that the key isn't present on the object (as opposed to simply being
57 // undefined).
58 EXPECT_FALSE(
59 parent_object->Has(context, gin::StringToV8(isolate(), "lastError"))
60 .ToChecked());
61
62 last_error.SetError(context, "Some last error");
63 EXPECT_EQ("\"Some last error\"", GetLastError(parent_object, context));
64
65 last_error.ClearError(context, false);
66 EXPECT_EQ("undefined", GetLastError(parent_object, context));
67 EXPECT_FALSE(
68 parent_object->Has(context, gin::StringToV8(isolate(), "lastError"))
69 .ToChecked());
70 }
71
72 // Test throwing an error if the last error wasn't checked.
73 TEST_F(APILastErrorTest, ReportIfUnchecked) {
74 v8::HandleScope handle_scope(isolate());
75 v8::Local<v8::Context> context = ContextLocal();
76 v8::Local<v8::Object> parent_object = v8::Object::New(isolate());
77
78 ParentList parents = {{context, parent_object}};
79 APILastError last_error(base::Bind(&GetParent, parents));
80
81 {
82 v8::TryCatch try_catch(isolate());
83 last_error.SetError(context, "foo");
84 // GetLastError() will count as accessing the error property, so we
85 // shouldn't throw an exception.
86 EXPECT_EQ("\"foo\"", GetLastError(parent_object, context));
87 last_error.ClearError(context, true);
88 EXPECT_FALSE(try_catch.HasCaught());
89 }
90
91 {
92 v8::TryCatch try_catch(isolate());
93 // This time, we should throw an exception.
94 last_error.SetError(context, "A last error");
95 last_error.ClearError(context, true);
96 ASSERT_TRUE(try_catch.HasCaught());
97 EXPECT_EQ("Uncaught Error: A last error",
98 gin::V8ToString(try_catch.Message()->Get()));
99 }
100 }
101
102 // Test behavior when something else sets a lastError property on the parent
103 // object.
104 TEST_F(APILastErrorTest, NonLastErrorObject) {
105 v8::HandleScope handle_scope(isolate());
106 v8::Local<v8::Context> context = ContextLocal();
107 v8::Local<v8::Object> parent_object = v8::Object::New(isolate());
108
109 ParentList parents = {{context, parent_object}};
110 APILastError last_error(base::Bind(&GetParent, parents));
111
112 auto checked_set = [context](v8::Local<v8::Object> object,
113 base::StringPiece key,
114 v8::Local<v8::Value> value) {
115 v8::Maybe<bool> success = object->Set(
116 context, gin::StringToSymbol(context->GetIsolate(), key), value);
117 ASSERT_TRUE(success.IsJust());
118 ASSERT_TRUE(success.FromJust());
119 };
120
121 // Set a "fake" lastError property on the parent.
122 v8::Local<v8::Object> fake_last_error = v8::Object::New(isolate());
123 checked_set(fake_last_error, "message",
124 gin::StringToV8(isolate(), "fake error"));
125 checked_set(parent_object, "lastError", fake_last_error);
126
127 EXPECT_EQ("\"fake error\"", GetLastError(parent_object, context));
128
129 // The bindings shouldn't mangle an existing property (or maybe we should -
130 // see the TODO in api_last_error.cc).
131 last_error.SetError(context, "Real last error");
132 EXPECT_EQ("\"fake error\"", GetLastError(parent_object, context));
133 last_error.ClearError(context, false);
134 EXPECT_EQ("\"fake error\"", GetLastError(parent_object, context));
135 }
136
137 // Test lastError in multiple different contexts.
138 TEST_F(APILastErrorTest, MultipleContexts) {
139 v8::HandleScope handle_scope(isolate());
140 v8::Local<v8::Context> context_a = ContextLocal();
141 v8::Local<v8::Context> context_b = v8::Context::New(isolate());
142 gin::ContextHolder holder_b(isolate());
143 holder_b.SetContext(context_b);
144
145 v8::Local<v8::Object> parent_a = v8::Object::New(isolate());
146 v8::Local<v8::Object> parent_b = v8::Object::New(isolate());
147 ParentList parents = {{context_a, parent_a}, {context_b, parent_b}};
148 APILastError last_error(base::Bind(&GetParent, parents));
149
150 last_error.SetError(context_a, "Last error a");
151 EXPECT_EQ("\"Last error a\"", GetLastError(parent_a, context_a));
152 EXPECT_EQ("undefined", GetLastError(parent_b, context_b));
153
154 last_error.SetError(context_b, "Last error b");
155 EXPECT_EQ("\"Last error a\"", GetLastError(parent_a, context_a));
156 EXPECT_EQ("\"Last error b\"", GetLastError(parent_b, context_b));
157
158 last_error.ClearError(context_b, false);
159 EXPECT_EQ("\"Last error a\"", GetLastError(parent_a, context_a));
160 EXPECT_EQ("undefined", GetLastError(parent_b, context_b));
161
162 last_error.ClearError(context_a, false);
163 EXPECT_EQ("undefined", GetLastError(parent_a, context_a));
164 EXPECT_EQ("undefined", GetLastError(parent_b, context_b));
165 }
166
167 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/api_last_error.cc ('k') | extensions/renderer/api_request_handler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698