1 // Copyright (c) 2011 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 "chrome/common/web_apps.h" 6 7 #include "base/file_path.h" 8 #include "base/file_util.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/path_service.h" 11 #include "base/utf_string_conversions.h" 12 #include "base/values.h" 13 #include "chrome/common/chrome_paths.h" 14 #include "chrome/common/json_schema_validator.h" 15 #include "content/common/json_value_serializer.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 namespace { 19 20 DictionaryValue* LoadDefinitionFile(const std::string& name) { 21 FilePath path; 22 if (!PathService::Get(chrome::DIR_TEST_DATA, &path)) { 23 ADD_FAILURE() << "Could not get test data dir."; 24 return NULL; 25 } 26 27 path = path.AppendASCII("web_app_info").AppendASCII(name.c_str()); 28 if (!file_util::PathExists(path)) { 29 ADD_FAILURE() << "Path does not exist: " << path.value(); 30 return NULL; 31 } 32 33 std::string error; 34 JSONFileValueSerializer serializer(path); 35 DictionaryValue* result = static_cast<DictionaryValue*>( 36 serializer.Deserialize(NULL, &error)); 37 if (!result) { 38 ADD_FAILURE() << "Error parsing " << name << ": " << error; 39 return NULL; 40 } 41 42 return result; 43 } 44 45 WebApplicationInfo* ParseFromDefinitionAndExpectSuccess( 46 const std::string& name) { 47 scoped_ptr<DictionaryValue> defintion(LoadDefinitionFile(name)); 48 if (!defintion.get()) 49 return NULL; 50 51 scoped_ptr<WebApplicationInfo> web_app(new WebApplicationInfo()); 52 web_app->manifest_url = GURL("http://example.com/"); 53 54 string16 error; 55 if (!web_apps::ParseWebAppFromDefinitionFile(defintion.get(), web_app.get(), 56 &error)) { 57 ADD_FAILURE() << "Error parsing " << name << ": " << UTF16ToUTF8(error); 58 return NULL; 59 } 60 61 return web_app.release(); 62 } 63 64 void ParseFromDefinitionAndExpectFailure(const std::string& name, 65 const string16& expected_error) { 66 scoped_ptr<DictionaryValue> definition(LoadDefinitionFile(name)); 67 if (!definition.get()) 68 return; 69 70 WebApplicationInfo web_app; 71 web_app.manifest_url = GURL("http://example.com/"); 72 73 string16 error; 74 if (web_apps::ParseWebAppFromDefinitionFile(definition.get(), &web_app, 75 &error)) { 76 ADD_FAILURE() << "Expected error parsing " << name 77 << " but parse succeeded."; 78 return; 79 } 80 81 EXPECT_EQ(UTF16ToUTF8(expected_error), UTF16ToUTF8(error)) << name; 82 } 83 84 } 85 86 TEST(WebAppInfo, ParseFromDefinitionFileErrors) { 87 // Test one definition file with a JSON schema error, just to make sure we're 88 // correctly propagating those. We don't extensively test all the properties 89 // covered by the schema, since we assume JSON schema is working correctly. 90 ParseFromDefinitionAndExpectFailure( 91 "missing_name.json", 92 UTF8ToUTF16(std::string("name: ") + 93 JSONSchemaValidator::kObjectPropertyIsRequired)); 94 95 ParseFromDefinitionAndExpectFailure( 96 "invalid_launch_url.json", 97 UTF8ToUTF16(WebApplicationInfo::kInvalidLaunchURL)); 98 99 ParseFromDefinitionAndExpectFailure( 100 "invalid_urls.json", 101 UTF8ToUTF16( 102 JSONSchemaValidator::FormatErrorMessage( 103 WebApplicationInfo::kInvalidURL, "2"))); 104 } 105 106 TEST(WebAppInfo, Minimal) { 107 scoped_ptr<WebApplicationInfo> web_app( 108 ParseFromDefinitionAndExpectSuccess("minimal.json")); 109 110 EXPECT_EQ(UTF8ToUTF16("hello"), web_app->title); 111 EXPECT_EQ(UTF8ToUTF16(""), web_app->description); 112 EXPECT_EQ(GURL("http://example.com/launch_url"), web_app->app_url); 113 EXPECT_EQ(0u, web_app->icons.size()); 114 EXPECT_EQ(0u, web_app->urls.size()); 115 EXPECT_EQ(0u, web_app->permissions.size()); 116 EXPECT_EQ("", web_app->launch_container); 117 } 118 119 TEST(WebAppInfo, Full) { 120 scoped_ptr<WebApplicationInfo> web_app( 121 ParseFromDefinitionAndExpectSuccess("full.json")); 122 123 EXPECT_EQ(UTF8ToUTF16("hello"), web_app->title); 124 EXPECT_EQ(UTF8ToUTF16("This app is super awesome"), web_app->description); 125 EXPECT_EQ(GURL("http://example.com/launch_url"), web_app->app_url); 126 ASSERT_EQ(1u, web_app->icons.size()); 127 EXPECT_EQ("http://example.com/16.png", web_app->icons[0].url.spec()); 128 EXPECT_EQ(16, web_app->icons[0].width); 129 EXPECT_EQ(16, web_app->icons[0].height); 130 ASSERT_EQ(2u, web_app->urls.size()); 131 EXPECT_EQ("http://example.com/foobar", web_app->urls[0].spec()); 132 EXPECT_EQ("http://example.com/baz", web_app->urls[1].spec()); 133 ASSERT_EQ(2u, web_app->permissions.size()); 134 EXPECT_EQ("geolocation", web_app->permissions[0]); 135 EXPECT_EQ("notifications", web_app->permissions[1]); 136 EXPECT_EQ("panel", web_app->launch_container); 137 } 138 139 // Tests ParseIconSizes with various input. 140 TEST(WebAppInfo, ParseIconSizes) { 141 struct TestData { 142 const char* input; 143 const bool expected_result; 144 const bool is_any; 145 const size_t expected_size_count; 146 const int width1; 147 const int height1; 148 const int width2; 149 const int height2; 150 } data[] = { 151 // Bogus input cases. 152 { "10", false, false, 0, 0, 0, 0, 0 }, 153 { "10 10", false, false, 0, 0, 0, 0, 0 }, 154 { "010", false, false, 0, 0, 0, 0, 0 }, 155 { " 010 ", false, false, 0, 0, 0, 0, 0 }, 156 { " 10x ", false, false, 0, 0, 0, 0, 0 }, 157 { " x10 ", false, false, 0, 0, 0, 0, 0 }, 158 { "any 10x10", false, false, 0, 0, 0, 0, 0 }, 159 { "", false, false, 0, 0, 0, 0, 0 }, 160 { "10ax11", false, false, 0, 0, 0, 0, 0 }, 161 162 // Any. 163 { "any", true, true, 0, 0, 0, 0, 0 }, 164 { " any", true, true, 0, 0, 0, 0, 0 }, 165 { " any ", true, true, 0, 0, 0, 0, 0 }, 166 167 // Sizes. 168 { "10x11", true, false, 1, 10, 11, 0, 0 }, 169 { " 10x11 ", true, false, 1, 10, 11, 0, 0 }, 170 { " 10x11 1x2", true, false, 2, 10, 11, 1, 2 }, 171 }; 172 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { 173 bool is_any; 174 std::vector<gfx::Size> sizes; 175 bool result = web_apps::ParseIconSizes(ASCIIToUTF16(data[i].input), &sizes, 176 &is_any); 177 ASSERT_EQ(result, data[i].expected_result); 178 if (result) { 179 ASSERT_EQ(data[i].is_any, is_any); 180 ASSERT_EQ(data[i].expected_size_count, sizes.size()); 181 if (!sizes.empty()) { 182 ASSERT_EQ(data[i].width1, sizes[0].width()); 183 ASSERT_EQ(data[i].height1, sizes[0].height()); 184 } 185 if (sizes.size() > 1) { 186 ASSERT_EQ(data[i].width2, sizes[1].width()); 187 ASSERT_EQ(data[i].height2, sizes[1].height()); 188 } 189 } 190 } 191 } 192