Revert "Only store leading 13 bits of password hash."
[chromium-blink-merge.git] / chrome / common / extensions / api / extension_api_unittest.cc
blob6fa80061acaf8a14c5a9fbfe6a0cf88667d1c9c1
1 // Copyright (c) 2012 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.
5 #include "extensions/common/extension_api.h"
7 #include <string>
8 #include <vector>
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/path_service.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/values.h"
19 #include "chrome/common/chrome_paths.h"
20 #include "extensions/common/extension.h"
21 #include "extensions/common/extension_builder.h"
22 #include "extensions/common/features/api_feature.h"
23 #include "extensions/common/features/base_feature_provider.h"
24 #include "extensions/common/features/simple_feature.h"
25 #include "extensions/common/manifest.h"
26 #include "extensions/common/manifest_constants.h"
27 #include "extensions/common/test_util.h"
28 #include "extensions/common/value_builder.h"
29 #include "testing/gtest/include/gtest/gtest.h"
31 namespace extensions {
33 using test_util::BuildExtension;
35 SimpleFeature* CreateAPIFeature() {
36 return new APIFeature();
39 TEST(ExtensionAPITest, Creation) {
40 ExtensionAPI* shared_instance = ExtensionAPI::GetSharedInstance();
41 EXPECT_EQ(shared_instance, ExtensionAPI::GetSharedInstance());
43 scoped_ptr<ExtensionAPI> new_instance(
44 ExtensionAPI::CreateWithDefaultConfiguration());
45 EXPECT_NE(new_instance.get(),
46 scoped_ptr<ExtensionAPI>(
47 ExtensionAPI::CreateWithDefaultConfiguration()).get());
49 ExtensionAPI empty_instance;
51 struct {
52 ExtensionAPI* api;
53 bool expect_populated;
54 } test_data[] = {
55 { shared_instance, true },
56 { new_instance.get(), true },
57 { &empty_instance, false }
60 for (size_t i = 0; i < arraysize(test_data); ++i) {
61 EXPECT_EQ(test_data[i].expect_populated,
62 test_data[i].api->GetSchema("bookmarks.create") != NULL);
66 TEST(ExtensionAPITest, SplitDependencyName) {
67 struct {
68 std::string input;
69 std::string expected_feature_type;
70 std::string expected_feature_name;
71 } test_data[] = {{"", "api", ""}, // assumes "api" when no type is present
72 {"foo", "api", "foo"},
73 {"foo:", "foo", ""},
74 {":foo", "", "foo"},
75 {"foo:bar", "foo", "bar"},
76 {"foo:bar.baz", "foo", "bar.baz"}};
78 for (size_t i = 0; i < arraysize(test_data); ++i) {
79 std::string feature_type;
80 std::string feature_name;
81 ExtensionAPI::SplitDependencyName(
82 test_data[i].input, &feature_type, &feature_name);
83 EXPECT_EQ(test_data[i].expected_feature_type, feature_type) << i;
84 EXPECT_EQ(test_data[i].expected_feature_name, feature_name) << i;
88 TEST(ExtensionAPITest, APIFeatures) {
89 struct {
90 std::string api_full_name;
91 bool expect_is_available;
92 Feature::Context context;
93 GURL url;
94 } test_data[] = {
95 { "test1", false, Feature::WEB_PAGE_CONTEXT, GURL() },
96 { "test1", true, Feature::BLESSED_EXTENSION_CONTEXT, GURL() },
97 { "test1", true, Feature::UNBLESSED_EXTENSION_CONTEXT, GURL() },
98 { "test1", true, Feature::CONTENT_SCRIPT_CONTEXT, GURL() },
99 { "test2", true, Feature::WEB_PAGE_CONTEXT, GURL("http://google.com") },
100 { "test2", false, Feature::BLESSED_EXTENSION_CONTEXT,
101 GURL("http://google.com") },
102 { "test2.foo", false, Feature::WEB_PAGE_CONTEXT,
103 GURL("http://google.com") },
104 { "test2.foo", true, Feature::CONTENT_SCRIPT_CONTEXT, GURL() },
105 { "test3", false, Feature::WEB_PAGE_CONTEXT, GURL("http://google.com") },
106 { "test3.foo", true, Feature::WEB_PAGE_CONTEXT, GURL("http://google.com") },
107 { "test3.foo", true, Feature::BLESSED_EXTENSION_CONTEXT,
108 GURL("http://bad.com") },
109 { "test4", true, Feature::BLESSED_EXTENSION_CONTEXT,
110 GURL("http://bad.com") },
111 { "test4.foo", false, Feature::BLESSED_EXTENSION_CONTEXT,
112 GURL("http://bad.com") },
113 { "test4.foo", false, Feature::UNBLESSED_EXTENSION_CONTEXT,
114 GURL("http://bad.com") },
115 { "test4.foo.foo", true, Feature::CONTENT_SCRIPT_CONTEXT, GURL() },
116 { "test5", true, Feature::WEB_PAGE_CONTEXT, GURL("http://foo.com") },
117 { "test5", false, Feature::WEB_PAGE_CONTEXT, GURL("http://bar.com") },
118 { "test5.blah", true, Feature::WEB_PAGE_CONTEXT, GURL("http://foo.com") },
119 { "test5.blah", false, Feature::WEB_PAGE_CONTEXT, GURL("http://bar.com") },
120 { "test6", false, Feature::BLESSED_EXTENSION_CONTEXT, GURL() },
121 { "test6.foo", true, Feature::BLESSED_EXTENSION_CONTEXT, GURL() },
122 { "test7", true, Feature::WEB_PAGE_CONTEXT, GURL("http://foo.com") },
123 { "test7.foo", false, Feature::WEB_PAGE_CONTEXT, GURL("http://bar.com") },
124 { "test7.foo", true, Feature::WEB_PAGE_CONTEXT, GURL("http://foo.com") },
125 { "test7.bar", false, Feature::WEB_PAGE_CONTEXT, GURL("http://bar.com") },
126 { "test7.bar", false, Feature::WEB_PAGE_CONTEXT, GURL("http://foo.com") },
128 // Test parent/child.
129 { "parent1", true, Feature::CONTENT_SCRIPT_CONTEXT, GURL() },
130 { "parent1", false, Feature::WEB_PAGE_CONTEXT, GURL("http://foo.com") },
131 { "parent1.child1", false, Feature::CONTENT_SCRIPT_CONTEXT, GURL() },
132 { "parent1.child1", true, Feature::WEB_PAGE_CONTEXT,
133 GURL("http://foo.com") },
134 { "parent1.child2", true, Feature::CONTENT_SCRIPT_CONTEXT, GURL() },
135 { "parent1.child2", false, Feature::WEB_PAGE_CONTEXT,
136 GURL("http://foo.com") },
137 { "parent2", true, Feature::CONTENT_SCRIPT_CONTEXT, GURL() },
138 { "parent2", true, Feature::BLESSED_EXTENSION_CONTEXT, GURL() },
139 { "parent2", true, Feature::UNBLESSED_EXTENSION_CONTEXT, GURL() },
140 { "parent2.child3", false, Feature::CONTENT_SCRIPT_CONTEXT, GURL() },
141 { "parent2.child3", true, Feature::BLESSED_EXTENSION_CONTEXT, GURL() },
142 { "parent2.child3", false, Feature::UNBLESSED_EXTENSION_CONTEXT, GURL() },
143 { "parent2.child3.child.child", true, Feature::CONTENT_SCRIPT_CONTEXT,
144 GURL() },
145 { "parent2.child3.child.child", false, Feature::BLESSED_EXTENSION_CONTEXT,
146 GURL() },
147 { "parent2.child3.child.child", true, Feature::UNBLESSED_EXTENSION_CONTEXT,
148 GURL() },
149 { "parent3", true, Feature::CONTENT_SCRIPT_CONTEXT, GURL() },
150 { "parent3", false, Feature::BLESSED_EXTENSION_CONTEXT, GURL() },
151 { "parent3", false, Feature::UNBLESSED_EXTENSION_CONTEXT, GURL() },
152 { "parent3.noparent", true, Feature::CONTENT_SCRIPT_CONTEXT, GURL() },
153 { "parent3.noparent", true, Feature::BLESSED_EXTENSION_CONTEXT, GURL() },
154 { "parent3.noparent", true, Feature::UNBLESSED_EXTENSION_CONTEXT, GURL() },
155 { "parent3.noparent.child", true, Feature::CONTENT_SCRIPT_CONTEXT, GURL() },
156 { "parent3.noparent.child", true, Feature::BLESSED_EXTENSION_CONTEXT,
157 GURL() },
158 { "parent3.noparent.child", true, Feature::UNBLESSED_EXTENSION_CONTEXT,
159 GURL() }
162 base::FilePath api_features_path;
163 PathService::Get(chrome::DIR_TEST_DATA, &api_features_path);
164 api_features_path = api_features_path.AppendASCII("extensions")
165 .AppendASCII("extension_api_unittest")
166 .AppendASCII("api_features.json");
168 std::string api_features_str;
169 ASSERT_TRUE(base::ReadFileToString(
170 api_features_path, &api_features_str)) << "api_features.json";
172 scoped_ptr<base::DictionaryValue> value(static_cast<base::DictionaryValue*>(
173 base::JSONReader::Read(api_features_str)));
174 BaseFeatureProvider api_feature_provider(*value, CreateAPIFeature);
176 for (size_t i = 0; i < arraysize(test_data); ++i) {
177 ExtensionAPI api;
178 api.RegisterDependencyProvider("api", &api_feature_provider);
179 for (base::DictionaryValue::Iterator iter(*value); !iter.IsAtEnd();
180 iter.Advance()) {
181 if (iter.key().find(".") == std::string::npos)
182 api.RegisterSchemaResource(iter.key(), 0);
185 ExtensionAPI::OverrideSharedInstanceForTest scope(&api);
186 bool expected = test_data[i].expect_is_available;
187 Feature::Availability availability =
188 api.IsAvailable(test_data[i].api_full_name,
189 NULL,
190 test_data[i].context,
191 test_data[i].url);
192 EXPECT_EQ(expected, availability.is_available())
193 << base::StringPrintf("Test %d: Feature '%s' was %s: %s",
194 static_cast<int>(i),
195 test_data[i].api_full_name.c_str(),
196 expected ? "not available" : "available",
197 availability.message().c_str());
201 TEST(ExtensionAPITest, IsAnyFeatureAvailableToContext) {
202 scoped_refptr<const Extension> app = ExtensionBuilder()
203 .SetManifest(DictionaryBuilder()
204 .Set("name", "app")
205 .Set("app", DictionaryBuilder()
206 .Set("background", DictionaryBuilder()
207 .Set("scripts", ListBuilder().Append("background.js"))))
208 .Set("version", "1")
209 .Set("manifest_version", 2)).Build();
210 scoped_refptr<const Extension> extension = ExtensionBuilder()
211 .SetManifest(DictionaryBuilder()
212 .Set("name", "extension")
213 .Set("version", "1")
214 .Set("manifest_version", 2)).Build();
216 struct {
217 std::string api_full_name;
218 bool expect_is_available;
219 Feature::Context context;
220 const Extension* extension;
221 GURL url;
222 } test_data[] = {
223 { "test1", false, Feature::WEB_PAGE_CONTEXT, NULL, GURL() },
224 { "test1", true, Feature::UNBLESSED_EXTENSION_CONTEXT, NULL, GURL() },
225 { "test1", false, Feature::UNBLESSED_EXTENSION_CONTEXT, app.get(), GURL() },
226 { "test1", true, Feature::UNBLESSED_EXTENSION_CONTEXT, extension.get(),
227 GURL() },
228 { "test2", true, Feature::CONTENT_SCRIPT_CONTEXT, NULL, GURL() },
229 { "test2", true, Feature::WEB_PAGE_CONTEXT, NULL,
230 GURL("http://google.com") },
231 { "test2.foo", false, Feature::WEB_PAGE_CONTEXT, NULL,
232 GURL("http://google.com") },
233 { "test3", true, Feature::CONTENT_SCRIPT_CONTEXT, NULL, GURL() },
234 { "test3", true, Feature::WEB_PAGE_CONTEXT, NULL, GURL("http://foo.com") },
235 { "test4.foo", true, Feature::CONTENT_SCRIPT_CONTEXT, NULL, GURL() },
236 { "test7", false, Feature::WEB_PAGE_CONTEXT, NULL,
237 GURL("http://google.com") },
238 { "test7", true, Feature::WEB_PAGE_CONTEXT, NULL, GURL("http://foo.com") },
239 { "test7", false, Feature::WEB_PAGE_CONTEXT, NULL, GURL("http://bar.com") }
242 base::FilePath api_features_path;
243 PathService::Get(chrome::DIR_TEST_DATA, &api_features_path);
244 api_features_path = api_features_path.AppendASCII("extensions")
245 .AppendASCII("extension_api_unittest")
246 .AppendASCII("api_features.json");
248 std::string api_features_str;
249 ASSERT_TRUE(base::ReadFileToString(
250 api_features_path, &api_features_str)) << "api_features.json";
252 scoped_ptr<base::DictionaryValue> value(static_cast<base::DictionaryValue*>(
253 base::JSONReader::Read(api_features_str)));
254 BaseFeatureProvider api_feature_provider(*value, CreateAPIFeature);
256 for (size_t i = 0; i < arraysize(test_data); ++i) {
257 ExtensionAPI api;
258 api.RegisterDependencyProvider("api", &api_feature_provider);
259 for (base::DictionaryValue::Iterator iter(*value); !iter.IsAtEnd();
260 iter.Advance()) {
261 if (iter.key().find(".") == std::string::npos)
262 api.RegisterSchemaResource(iter.key(), 0);
265 Feature* test_feature =
266 api_feature_provider.GetFeature(test_data[i].api_full_name);
267 ASSERT_TRUE(test_feature);
268 EXPECT_EQ(test_data[i].expect_is_available,
269 api.IsAnyFeatureAvailableToContext(*test_feature,
270 test_data[i].extension,
271 test_data[i].context,
272 test_data[i].url))
273 << i;
277 TEST(ExtensionAPITest, LazyGetSchema) {
278 scoped_ptr<ExtensionAPI> apis(ExtensionAPI::CreateWithDefaultConfiguration());
280 EXPECT_EQ(NULL, apis->GetSchema(std::string()));
281 EXPECT_EQ(NULL, apis->GetSchema(std::string()));
282 EXPECT_EQ(NULL, apis->GetSchema("experimental"));
283 EXPECT_EQ(NULL, apis->GetSchema("experimental"));
284 EXPECT_EQ(NULL, apis->GetSchema("foo"));
285 EXPECT_EQ(NULL, apis->GetSchema("foo"));
287 EXPECT_TRUE(apis->GetSchema("dns"));
288 EXPECT_TRUE(apis->GetSchema("dns"));
289 EXPECT_TRUE(apis->GetSchema("extension"));
290 EXPECT_TRUE(apis->GetSchema("extension"));
291 EXPECT_TRUE(apis->GetSchema("infobars"));
292 EXPECT_TRUE(apis->GetSchema("infobars"));
293 EXPECT_TRUE(apis->GetSchema("omnibox"));
294 EXPECT_TRUE(apis->GetSchema("omnibox"));
295 EXPECT_TRUE(apis->GetSchema("storage"));
296 EXPECT_TRUE(apis->GetSchema("storage"));
299 scoped_refptr<Extension> CreateExtensionWithPermissions(
300 const std::set<std::string>& permissions) {
301 base::DictionaryValue manifest;
302 manifest.SetString("name", "extension");
303 manifest.SetString("version", "1.0");
304 manifest.SetInteger("manifest_version", 2);
306 scoped_ptr<base::ListValue> permissions_list(new base::ListValue());
307 for (std::set<std::string>::const_iterator i = permissions.begin();
308 i != permissions.end(); ++i) {
309 permissions_list->Append(new base::StringValue(*i));
311 manifest.Set("permissions", permissions_list.release());
314 std::string error;
315 scoped_refptr<Extension> extension(Extension::Create(
316 base::FilePath(), Manifest::UNPACKED,
317 manifest, Extension::NO_FLAGS, &error));
318 CHECK(extension.get());
319 CHECK(error.empty());
321 return extension;
324 scoped_refptr<Extension> CreateExtensionWithPermission(
325 const std::string& permission) {
326 std::set<std::string> permissions;
327 permissions.insert(permission);
328 return CreateExtensionWithPermissions(permissions);
331 TEST(ExtensionAPITest, ExtensionWithUnprivilegedAPIs) {
332 scoped_refptr<Extension> extension;
334 std::set<std::string> permissions;
335 permissions.insert("storage");
336 permissions.insert("history");
337 extension = CreateExtensionWithPermissions(permissions);
340 scoped_ptr<ExtensionAPI> extension_api(
341 ExtensionAPI::CreateWithDefaultConfiguration());
343 const FeatureProvider& api_features = *FeatureProvider::GetAPIFeatures();
345 // "storage" is completely unprivileged.
346 EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
347 *api_features.GetFeature("storage"),
348 NULL,
349 Feature::BLESSED_EXTENSION_CONTEXT,
350 GURL()));
351 EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
352 *api_features.GetFeature("storage"),
353 NULL,
354 Feature::UNBLESSED_EXTENSION_CONTEXT,
355 GURL()));
356 EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
357 *api_features.GetFeature("storage"),
358 NULL,
359 Feature::CONTENT_SCRIPT_CONTEXT,
360 GURL()));
362 // "extension" is partially unprivileged.
363 EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
364 *api_features.GetFeature("extension"),
365 NULL,
366 Feature::BLESSED_EXTENSION_CONTEXT,
367 GURL()));
368 EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
369 *api_features.GetFeature("extension"),
370 NULL,
371 Feature::UNBLESSED_EXTENSION_CONTEXT,
372 GURL()));
373 EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
374 *api_features.GetFeature("extension"),
375 NULL,
376 Feature::CONTENT_SCRIPT_CONTEXT,
377 GURL()));
378 EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
379 *api_features.GetFeature("extension.getURL"),
380 NULL,
381 Feature::CONTENT_SCRIPT_CONTEXT,
382 GURL()));
384 // "history" is entirely privileged.
385 EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
386 *api_features.GetFeature("history"),
387 NULL,
388 Feature::BLESSED_EXTENSION_CONTEXT,
389 GURL()));
390 EXPECT_FALSE(extension_api->IsAnyFeatureAvailableToContext(
391 *api_features.GetFeature("history"),
392 NULL,
393 Feature::UNBLESSED_EXTENSION_CONTEXT,
394 GURL()));
395 EXPECT_FALSE(extension_api->IsAnyFeatureAvailableToContext(
396 *api_features.GetFeature("history"),
397 NULL,
398 Feature::CONTENT_SCRIPT_CONTEXT,
399 GURL()));
402 scoped_refptr<Extension> CreateHostedApp() {
403 base::DictionaryValue values;
404 values.SetString(manifest_keys::kName, "test");
405 values.SetString(manifest_keys::kVersion, "0.1");
406 values.Set(manifest_keys::kWebURLs, new base::ListValue());
407 values.SetString(manifest_keys::kLaunchWebURL,
408 "http://www.example.com");
409 std::string error;
410 scoped_refptr<Extension> extension(Extension::Create(
411 base::FilePath(), Manifest::INTERNAL, values, Extension::NO_FLAGS,
412 &error));
413 CHECK(extension.get());
414 return extension;
417 scoped_refptr<Extension> CreatePackagedAppWithPermissions(
418 const std::set<std::string>& permissions) {
419 base::DictionaryValue values;
420 values.SetString(manifest_keys::kName, "test");
421 values.SetString(manifest_keys::kVersion, "0.1");
422 values.SetString(manifest_keys::kPlatformAppBackground,
423 "http://www.example.com");
425 base::DictionaryValue* app = new base::DictionaryValue();
426 base::DictionaryValue* background = new base::DictionaryValue();
427 base::ListValue* scripts = new base::ListValue();
428 scripts->Append(new base::StringValue("test.js"));
429 background->Set("scripts", scripts);
430 app->Set("background", background);
431 values.Set(manifest_keys::kApp, app);
433 scoped_ptr<base::ListValue> permissions_list(new base::ListValue());
434 for (std::set<std::string>::const_iterator i = permissions.begin();
435 i != permissions.end(); ++i) {
436 permissions_list->Append(new base::StringValue(*i));
438 values.Set("permissions", permissions_list.release());
441 std::string error;
442 scoped_refptr<Extension> extension(Extension::Create(
443 base::FilePath(), Manifest::INTERNAL, values, Extension::NO_FLAGS,
444 &error));
445 CHECK(extension.get()) << error;
446 return extension;
449 TEST(ExtensionAPITest, HostedAppPermissions) {
450 scoped_refptr<Extension> extension = CreateHostedApp();
452 scoped_ptr<ExtensionAPI> extension_api(
453 ExtensionAPI::CreateWithDefaultConfiguration());
455 // "runtime" and "tabs" should not be available in hosted apps.
456 EXPECT_FALSE(extension_api->IsAvailable("runtime",
457 extension.get(),
458 Feature::BLESSED_EXTENSION_CONTEXT,
459 GURL()).is_available());
460 EXPECT_FALSE(extension_api->IsAvailable("runtime.id",
461 extension.get(),
462 Feature::BLESSED_EXTENSION_CONTEXT,
463 GURL()).is_available());
464 EXPECT_FALSE(extension_api->IsAvailable("runtime.sendMessage",
465 extension.get(),
466 Feature::BLESSED_EXTENSION_CONTEXT,
467 GURL()).is_available());
468 EXPECT_FALSE(extension_api->IsAvailable("runtime.sendNativeMessage",
469 extension.get(),
470 Feature::BLESSED_EXTENSION_CONTEXT,
471 GURL()).is_available());
472 EXPECT_FALSE(extension_api->IsAvailable("tabs.create",
473 extension.get(),
474 Feature::BLESSED_EXTENSION_CONTEXT,
475 GURL()).is_available());
478 TEST(ExtensionAPITest, AppAndFriendsAvailability) {
480 scoped_ptr<ExtensionAPI> extension_api(
481 ExtensionAPI::CreateWithDefaultConfiguration());
483 // Make sure chrome.app.runtime and chrome.app.window are available to apps,
484 // and chrome.app is not.
486 std::set<std::string> permissions;
487 permissions.insert("app.runtime");
488 permissions.insert("app.window");
489 scoped_refptr<Extension> extension =
490 CreatePackagedAppWithPermissions(permissions);
491 EXPECT_FALSE(extension_api->IsAvailable(
492 "app",
493 extension.get(),
494 Feature::BLESSED_EXTENSION_CONTEXT,
495 GURL("http://foo.com")).is_available());
496 EXPECT_TRUE(extension_api->IsAvailable(
497 "app.runtime",
498 extension.get(),
499 Feature::BLESSED_EXTENSION_CONTEXT,
500 GURL("http://foo.com")).is_available());
501 EXPECT_TRUE(extension_api->IsAvailable(
502 "app.window",
503 extension.get(),
504 Feature::BLESSED_EXTENSION_CONTEXT,
505 GURL("http://foo.com")).is_available());
507 // Make sure chrome.app.runtime and chrome.app.window are not available to
508 // extensions, and chrome.app is.
510 std::set<std::string> permissions;
511 scoped_refptr<Extension> extension =
512 CreateExtensionWithPermissions(permissions);
513 EXPECT_TRUE(extension_api->IsAvailable(
514 "app",
515 extension.get(),
516 Feature::BLESSED_EXTENSION_CONTEXT,
517 GURL("http://foo.com")).is_available());
518 EXPECT_FALSE(extension_api->IsAvailable(
519 "app.runtime",
520 extension.get(),
521 Feature::BLESSED_EXTENSION_CONTEXT,
522 GURL("http://foo.com")).is_available());
523 EXPECT_FALSE(extension_api->IsAvailable(
524 "app.window",
525 extension.get(),
526 Feature::BLESSED_EXTENSION_CONTEXT,
527 GURL("http://foo.com")).is_available());
531 TEST(ExtensionAPITest, ExtensionWithDependencies) {
532 // Extension with the "ttsEngine" permission but not the "tts" permission; it
533 // should not automatically get "tts" permission.
535 scoped_refptr<Extension> extension =
536 CreateExtensionWithPermission("ttsEngine");
537 scoped_ptr<ExtensionAPI> api(
538 ExtensionAPI::CreateWithDefaultConfiguration());
539 EXPECT_TRUE(api->IsAvailable("ttsEngine",
540 extension.get(),
541 Feature::BLESSED_EXTENSION_CONTEXT,
542 GURL()).is_available());
543 EXPECT_FALSE(api->IsAvailable("tts",
544 extension.get(),
545 Feature::BLESSED_EXTENSION_CONTEXT,
546 GURL()).is_available());
549 // Conversely, extension with the "tts" permission but not the "ttsEngine"
550 // permission shouldn't get the "ttsEngine" permission.
552 scoped_refptr<Extension> extension =
553 CreateExtensionWithPermission("tts");
554 scoped_ptr<ExtensionAPI> api(
555 ExtensionAPI::CreateWithDefaultConfiguration());
556 EXPECT_FALSE(api->IsAvailable("ttsEngine",
557 extension.get(),
558 Feature::BLESSED_EXTENSION_CONTEXT,
559 GURL()).is_available());
560 EXPECT_TRUE(api->IsAvailable("tts",
561 extension.get(),
562 Feature::BLESSED_EXTENSION_CONTEXT,
563 GURL()).is_available());
567 bool MatchesURL(
568 ExtensionAPI* api, const std::string& api_name, const std::string& url) {
569 return api->IsAvailable(
570 api_name, NULL, Feature::WEB_PAGE_CONTEXT, GURL(url)).is_available();
573 TEST(ExtensionAPITest, URLMatching) {
574 scoped_ptr<ExtensionAPI> api(ExtensionAPI::CreateWithDefaultConfiguration());
576 // "app" API is available to all URLs that content scripts can be injected.
577 EXPECT_TRUE(MatchesURL(api.get(), "app", "http://example.com/example.html"));
578 EXPECT_TRUE(MatchesURL(api.get(), "app", "https://blah.net"));
579 EXPECT_TRUE(MatchesURL(api.get(), "app", "file://somefile.html"));
581 // Also to internal URLs.
582 EXPECT_TRUE(MatchesURL(api.get(), "app", "about:flags"));
583 EXPECT_TRUE(MatchesURL(api.get(), "app", "chrome://flags"));
585 // "app" should be available to chrome-extension URLs.
586 EXPECT_TRUE(MatchesURL(api.get(), "app",
587 "chrome-extension://fakeextension"));
589 // "storage" API (for example) isn't available to any URLs.
590 EXPECT_FALSE(MatchesURL(api.get(), "storage",
591 "http://example.com/example.html"));
592 EXPECT_FALSE(MatchesURL(api.get(), "storage", "https://blah.net"));
593 EXPECT_FALSE(MatchesURL(api.get(), "storage", "file://somefile.html"));
594 EXPECT_FALSE(MatchesURL(api.get(), "storage", "about:flags"));
595 EXPECT_FALSE(MatchesURL(api.get(), "storage", "chrome://flags"));
596 EXPECT_FALSE(MatchesURL(api.get(), "storage",
597 "chrome-extension://fakeextension"));
600 TEST(ExtensionAPITest, GetAPINameFromFullName) {
601 struct {
602 std::string input;
603 std::string api_name;
604 std::string child_name;
605 } test_data[] = {
606 { "", "", "" },
607 { "unknown", "", "" },
608 { "bookmarks", "bookmarks", "" },
609 { "bookmarks.", "bookmarks", "" },
610 { ".bookmarks", "", "" },
611 { "bookmarks.create", "bookmarks", "create" },
612 { "bookmarks.create.", "bookmarks", "create." },
613 { "bookmarks.create.monkey", "bookmarks", "create.monkey" },
614 { "bookmarkManagerPrivate", "bookmarkManagerPrivate", "" },
615 { "bookmarkManagerPrivate.copy", "bookmarkManagerPrivate", "copy" }
618 scoped_ptr<ExtensionAPI> api(ExtensionAPI::CreateWithDefaultConfiguration());
619 for (size_t i = 0; i < arraysize(test_data); ++i) {
620 std::string child_name;
621 std::string api_name = api->GetAPINameFromFullName(test_data[i].input,
622 &child_name);
623 EXPECT_EQ(test_data[i].api_name, api_name) << test_data[i].input;
624 EXPECT_EQ(test_data[i].child_name, child_name) << test_data[i].input;
628 TEST(ExtensionAPITest, DefaultConfigurationFeatures) {
629 scoped_ptr<ExtensionAPI> api(ExtensionAPI::CreateWithDefaultConfiguration());
631 SimpleFeature* bookmarks = static_cast<SimpleFeature*>(
632 api->GetFeatureDependency("api:bookmarks"));
633 SimpleFeature* bookmarks_create = static_cast<SimpleFeature*>(
634 api->GetFeatureDependency("api:bookmarks.create"));
636 struct {
637 SimpleFeature* feature;
638 // TODO(aa): More stuff to test over time.
639 } test_data[] = {
640 { bookmarks },
641 { bookmarks_create }
644 for (size_t i = 0; i < arraysize(test_data); ++i) {
645 SimpleFeature* feature = test_data[i].feature;
646 ASSERT_TRUE(feature) << i;
648 EXPECT_TRUE(feature->whitelist()->empty());
649 EXPECT_TRUE(feature->extension_types()->empty());
651 EXPECT_EQ(SimpleFeature::UNSPECIFIED_LOCATION, feature->location());
652 EXPECT_TRUE(feature->platforms()->empty());
653 EXPECT_EQ(0, feature->min_manifest_version());
654 EXPECT_EQ(0, feature->max_manifest_version());
658 TEST(ExtensionAPITest, FeaturesRequireContexts) {
659 // TODO(cduvall): Make this check API featues.
660 scoped_ptr<base::DictionaryValue> api_features1(new base::DictionaryValue());
661 scoped_ptr<base::DictionaryValue> api_features2(new base::DictionaryValue());
662 base::DictionaryValue* test1 = new base::DictionaryValue();
663 base::DictionaryValue* test2 = new base::DictionaryValue();
664 base::ListValue* contexts = new base::ListValue();
665 contexts->Append(new base::StringValue("content_script"));
666 test1->Set("contexts", contexts);
667 test1->SetString("channel", "stable");
668 test2->SetString("channel", "stable");
669 api_features1->Set("test", test1);
670 api_features2->Set("test", test2);
672 struct {
673 base::DictionaryValue* api_features;
674 bool expect_success;
675 } test_data[] = {
676 { api_features1.get(), true },
677 { api_features2.get(), false }
680 for (size_t i = 0; i < arraysize(test_data); ++i) {
681 BaseFeatureProvider api_feature_provider(*test_data[i].api_features,
682 CreateAPIFeature);
683 Feature* feature = api_feature_provider.GetFeature("test");
684 EXPECT_EQ(test_data[i].expect_success, feature != NULL) << i;
688 static void GetDictionaryFromList(const base::DictionaryValue* schema,
689 const std::string& list_name,
690 const int list_index,
691 const base::DictionaryValue** out) {
692 const base::ListValue* list;
693 EXPECT_TRUE(schema->GetList(list_name, &list));
694 EXPECT_TRUE(list->GetDictionary(list_index, out));
697 TEST(ExtensionAPITest, TypesHaveNamespace) {
698 base::FilePath manifest_path;
699 PathService::Get(chrome::DIR_TEST_DATA, &manifest_path);
700 manifest_path = manifest_path.AppendASCII("extensions")
701 .AppendASCII("extension_api_unittest")
702 .AppendASCII("types_have_namespace.json");
704 std::string manifest_str;
705 ASSERT_TRUE(base::ReadFileToString(manifest_path, &manifest_str))
706 << "Failed to load: " << manifest_path.value();
708 ExtensionAPI api;
709 api.RegisterSchemaResource("test.foo", 0);
710 api.LoadSchema("test.foo", manifest_str);
712 const base::DictionaryValue* schema = api.GetSchema("test.foo");
714 const base::DictionaryValue* dict;
715 const base::DictionaryValue* sub_dict;
716 std::string type;
718 GetDictionaryFromList(schema, "types", 0, &dict);
719 EXPECT_TRUE(dict->GetString("id", &type));
720 EXPECT_EQ("test.foo.TestType", type);
721 EXPECT_TRUE(dict->GetString("customBindings", &type));
722 EXPECT_EQ("test.foo.TestType", type);
723 EXPECT_TRUE(dict->GetDictionary("properties", &sub_dict));
724 const base::DictionaryValue* property;
725 EXPECT_TRUE(sub_dict->GetDictionary("foo", &property));
726 EXPECT_TRUE(property->GetString("$ref", &type));
727 EXPECT_EQ("test.foo.OtherType", type);
728 EXPECT_TRUE(sub_dict->GetDictionary("bar", &property));
729 EXPECT_TRUE(property->GetString("$ref", &type));
730 EXPECT_EQ("fully.qualified.Type", type);
732 GetDictionaryFromList(schema, "functions", 0, &dict);
733 GetDictionaryFromList(dict, "parameters", 0, &sub_dict);
734 EXPECT_TRUE(sub_dict->GetString("$ref", &type));
735 EXPECT_EQ("test.foo.TestType", type);
736 EXPECT_TRUE(dict->GetDictionary("returns", &sub_dict));
737 EXPECT_TRUE(sub_dict->GetString("$ref", &type));
738 EXPECT_EQ("fully.qualified.Type", type);
740 GetDictionaryFromList(schema, "functions", 1, &dict);
741 GetDictionaryFromList(dict, "parameters", 0, &sub_dict);
742 EXPECT_TRUE(sub_dict->GetString("$ref", &type));
743 EXPECT_EQ("fully.qualified.Type", type);
744 EXPECT_TRUE(dict->GetDictionary("returns", &sub_dict));
745 EXPECT_TRUE(sub_dict->GetString("$ref", &type));
746 EXPECT_EQ("test.foo.TestType", type);
748 GetDictionaryFromList(schema, "events", 0, &dict);
749 GetDictionaryFromList(dict, "parameters", 0, &sub_dict);
750 EXPECT_TRUE(sub_dict->GetString("$ref", &type));
751 EXPECT_EQ("test.foo.TestType", type);
752 GetDictionaryFromList(dict, "parameters", 1, &sub_dict);
753 EXPECT_TRUE(sub_dict->GetString("$ref", &type));
754 EXPECT_EQ("fully.qualified.Type", type);
757 // Tests API availability with an empty manifest.
758 TEST(ExtensionAPITest, NoPermissions) {
759 const struct {
760 const char* permission_name;
761 bool expect_success;
762 } kTests[] = {
763 // Test default module/package permission.
764 { "extension", true },
765 { "i18n", true },
766 { "permissions", true },
767 { "runtime", true },
768 { "test", true },
769 // These require manifest keys.
770 { "browserAction", false },
771 { "pageAction", false },
772 { "pageActions", false },
773 // Some negative tests.
774 { "bookmarks", false },
775 { "cookies", false },
776 { "history", false },
777 // Make sure we find the module name after stripping '.'
778 { "runtime.abcd.onStartup", true },
779 // Test Tabs/Windows functions.
780 { "tabs.create", true },
781 { "tabs.duplicate", true },
782 { "tabs.onRemoved", true },
783 { "tabs.remove", true },
784 { "tabs.update", true },
785 { "tabs.getSelected", true },
786 { "tabs.onUpdated", true },
787 { "windows.get", true },
788 { "windows.create", true },
789 { "windows.remove", true },
790 { "windows.update", true },
791 // Test some whitelisted functions. These require no permissions.
792 { "app.getDetails", true },
793 { "app.getDetailsForFrame", true },
794 { "app.getIsInstalled", true },
795 { "app.installState", true },
796 { "app.runningState", true },
797 { "management.getPermissionWarningsByManifest", true },
798 { "management.uninstallSelf", true },
799 // But other functions in those modules do.
800 { "management.getPermissionWarningsById", false },
801 { "runtime.connectNative", false },
804 scoped_ptr<ExtensionAPI> extension_api(
805 ExtensionAPI::CreateWithDefaultConfiguration());
806 scoped_refptr<Extension> extension =
807 BuildExtension(ExtensionBuilder().Pass()).Build();
809 for (size_t i = 0; i < arraysize(kTests); ++i) {
810 EXPECT_EQ(kTests[i].expect_success,
811 extension_api->IsAvailable(kTests[i].permission_name,
812 extension.get(),
813 Feature::BLESSED_EXTENSION_CONTEXT,
814 GURL()).is_available())
815 << "Permission being tested: " << kTests[i].permission_name;
819 // Tests that permissions that require manifest keys are available when those
820 // keys are present.
821 TEST(ExtensionAPITest, ManifestKeys) {
822 scoped_ptr<ExtensionAPI> extension_api(
823 ExtensionAPI::CreateWithDefaultConfiguration());
825 scoped_refptr<Extension> extension =
826 BuildExtension(ExtensionBuilder().Pass())
827 .MergeManifest(DictionaryBuilder().Set("browser_action",
828 DictionaryBuilder().Pass()))
829 .Build();
831 EXPECT_TRUE(extension_api->IsAvailable("browserAction",
832 extension.get(),
833 Feature::BLESSED_EXTENSION_CONTEXT,
834 GURL()).is_available());
835 EXPECT_FALSE(extension_api->IsAvailable("pageAction",
836 extension.get(),
837 Feature::BLESSED_EXTENSION_CONTEXT,
838 GURL()).is_available());
841 } // namespace extensions