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

Side by Side Diff: chrome/browser/shell_integration_unittest.cc

Issue 12321107: Move shell integration code from chrome/browser to apps (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 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 | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/shell_integration.h"
6
7 #include <cstdlib>
8 #include <map>
9
10 #include "base/file_util.h"
11 #include "base/files/file_path.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/message_loop.h"
14 #include "base/stl_util.h"
15 #include "base/string_util.h"
16 #include "base/utf_string_conversions.h"
17 #include "chrome/browser/web_applications/web_app.h"
18 #include "chrome/common/chrome_constants.h"
19 #include "content/public/test/test_browser_thread.h"
20 #include "googleurl/src/gurl.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 #if defined(OS_POSIX) && !defined(OS_MACOSX)
24 #include "base/environment.h"
25 #include "chrome/browser/shell_integration_linux.h"
26 #endif
27
28 #define FPL FILE_PATH_LITERAL
29
30 using content::BrowserThread;
31
32 #if defined(OS_POSIX) && !defined(OS_MACOSX)
33 namespace {
34
35 // Provides mock environment variables values based on a stored map.
36 class MockEnvironment : public base::Environment {
37 public:
38 MockEnvironment() {}
39
40 void Set(const std::string& name, const std::string& value) {
41 variables_[name] = value;
42 }
43
44 virtual bool GetVar(const char* variable_name, std::string* result) OVERRIDE {
45 if (ContainsKey(variables_, variable_name)) {
46 *result = variables_[variable_name];
47 return true;
48 }
49
50 return false;
51 }
52
53 virtual bool SetVar(const char* variable_name,
54 const std::string& new_value) OVERRIDE {
55 ADD_FAILURE();
56 return false;
57 }
58
59 virtual bool UnSetVar(const char* variable_name) OVERRIDE {
60 ADD_FAILURE();
61 return false;
62 }
63
64 private:
65 std::map<std::string, std::string> variables_;
66
67 DISALLOW_COPY_AND_ASSIGN(MockEnvironment);
68 };
69
70 // Allows you to change the real environment, but reverts changes upon
71 // destruction.
72 class ScopedEnvironment {
73 public:
74 ScopedEnvironment() {}
75
76 ~ScopedEnvironment() {
77 for (std::map<std::string, std::string>::const_iterator
78 it = old_variables_.begin(); it != old_variables_.end(); ++it) {
79 if (it->second.empty()) {
80 unsetenv(it->first.c_str());
81 } else {
82 setenv(it->first.c_str(), it->second.c_str(), 1);
83 }
84 }
85 }
86
87 void Set(const std::string& name, const std::string& value) {
88 if (!ContainsKey(old_variables_, name)) {
89 const char* value = getenv(name.c_str());
90 if (value != NULL) {
91 old_variables_[name] = value;
92 } else {
93 old_variables_[name] = std::string();
94 }
95 }
96 setenv(name.c_str(), value.c_str(), 1);
97 }
98
99 private:
100 // Map from name to original value, or the empty string if there was no
101 // previous value.
102 std::map<std::string, std::string> old_variables_;
103
104 DISALLOW_COPY_AND_ASSIGN(ScopedEnvironment);
105 };
106
107 } // namespace
108
109 TEST(ShellIntegrationTest, GetDesktopShortcutTemplate) {
110 #if defined(GOOGLE_CHROME_BUILD)
111 const char kTemplateFilename[] = "google-chrome.desktop";
112 #else // CHROMIUM_BUILD
113 const char kTemplateFilename[] = "chromium-browser.desktop";
114 #endif
115
116 const char kTestData1[] = "a magical testing string";
117 const char kTestData2[] = "a different testing string";
118
119 MessageLoop message_loop;
120 content::TestBrowserThread file_thread(BrowserThread::FILE, &message_loop);
121
122 {
123 base::ScopedTempDir temp_dir;
124 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
125
126 MockEnvironment env;
127 env.Set("XDG_DATA_HOME", temp_dir.path().value());
128 ASSERT_TRUE(file_util::WriteFile(
129 temp_dir.path().AppendASCII(kTemplateFilename),
130 kTestData1, strlen(kTestData1)));
131 std::string contents;
132 ASSERT_TRUE(ShellIntegrationLinux::GetDesktopShortcutTemplate(&env,
133 &contents));
134 EXPECT_EQ(kTestData1, contents);
135 }
136
137 {
138 base::ScopedTempDir temp_dir;
139 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
140
141 MockEnvironment env;
142 env.Set("XDG_DATA_DIRS", temp_dir.path().value());
143 ASSERT_TRUE(file_util::CreateDirectory(
144 temp_dir.path().AppendASCII("applications")));
145 ASSERT_TRUE(file_util::WriteFile(
146 temp_dir.path().AppendASCII("applications")
147 .AppendASCII(kTemplateFilename),
148 kTestData2, strlen(kTestData2)));
149 std::string contents;
150 ASSERT_TRUE(ShellIntegrationLinux::GetDesktopShortcutTemplate(&env,
151 &contents));
152 EXPECT_EQ(kTestData2, contents);
153 }
154
155 {
156 base::ScopedTempDir temp_dir;
157 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
158
159 MockEnvironment env;
160 env.Set("XDG_DATA_DIRS", temp_dir.path().value() + ":" +
161 temp_dir.path().AppendASCII("applications").value());
162 ASSERT_TRUE(file_util::CreateDirectory(
163 temp_dir.path().AppendASCII("applications")));
164 ASSERT_TRUE(file_util::WriteFile(
165 temp_dir.path().AppendASCII(kTemplateFilename),
166 kTestData1, strlen(kTestData1)));
167 ASSERT_TRUE(file_util::WriteFile(
168 temp_dir.path().AppendASCII("applications")
169 .AppendASCII(kTemplateFilename),
170 kTestData2, strlen(kTestData2)));
171 std::string contents;
172 ASSERT_TRUE(ShellIntegrationLinux::GetDesktopShortcutTemplate(&env,
173 &contents));
174 EXPECT_EQ(kTestData1, contents);
175 }
176 }
177
178 TEST(ShellIntegrationTest, GetWebShortcutFilename) {
179 const struct {
180 const base::FilePath::CharType* path;
181 const char* url;
182 } test_cases[] = {
183 { FPL("http___foo_.desktop"), "http://foo" },
184 { FPL("http___foo_bar_.desktop"), "http://foo/bar/" },
185 { FPL("http___foo_bar_a=b&c=d.desktop"), "http://foo/bar?a=b&c=d" },
186
187 // Now we're starting to be more evil...
188 { FPL("http___foo_.desktop"), "http://foo/bar/baz/../../../../../" },
189 { FPL("http___foo_.desktop"), "http://foo/bar/././../baz/././../" },
190 { FPL("http___.._.desktop"), "http://../../../../" },
191 };
192 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); i++) {
193 EXPECT_EQ(std::string(chrome::kBrowserProcessExecutableName) + "-" +
194 test_cases[i].path,
195 ShellIntegrationLinux::GetWebShortcutFilename(
196 GURL(test_cases[i].url)).value()) <<
197 " while testing " << test_cases[i].url;
198 }
199 }
200
201 TEST(ShellIntegrationTest, GetDesktopFileContents) {
202 const struct {
203 const char* url;
204 const char* title;
205 const char* icon_name;
206 const char* template_contents;
207 const char* expected_output;
208 } test_cases[] = {
209 // Dumb case.
210 { "ignored", "ignored", "ignored", "", "#!/usr/bin/env xdg-open\n" },
211
212 // Real-world case.
213 { "http://gmail.com",
214 "GMail",
215 "chrome-http__gmail.com",
216
217 "[Desktop Entry]\n"
218 "Version=1.0\n"
219 "Encoding=UTF-8\n"
220 "Name=Google Chrome\n"
221 "GenericName=Web Browser\n"
222 "Comment=The web browser from Google\n"
223 "Exec=/opt/google/chrome/google-chrome %U\n"
224 "Terminal=false\n"
225 "Icon=/opt/google/chrome/product_logo_48.png\n"
226 "Type=Application\n"
227 "Categories=Application;Network;WebBrowser;\n"
228 "MimeType=text/html;text/xml;application/xhtml_xml;\n"
229 "X-Ayatana-Desktop-Shortcuts=NewWindow;\n"
230 "\n"
231 "[NewWindow Shortcut Group]\n"
232 "Name=Open New Window\n"
233 "Exec=/opt/google/chrome/google-chrome\n"
234 "TargetEnvironment=Unity\n",
235
236 "#!/usr/bin/env xdg-open\n"
237 "[Desktop Entry]\n"
238 "Version=1.0\n"
239 "Encoding=UTF-8\n"
240 "Name=GMail\n"
241 "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
242 "Terminal=false\n"
243 "Icon=chrome-http__gmail.com\n"
244 "Type=Application\n"
245 "Categories=Application;Network;WebBrowser;\n"
246 #if !defined(USE_AURA)
247 // Aura Chrome does not (yet) set WMClass, so we only expect
248 // StartupWMClass on non-Aura builds.
249 "StartupWMClass=gmail.com\n"
250 #endif
251 },
252
253 // Make sure we don't insert duplicate shebangs.
254 { "http://gmail.com",
255 "GMail",
256 "chrome-http__gmail.com",
257
258 "#!/some/shebang\n"
259 "[Desktop Entry]\n"
260 "Name=Google Chrome\n"
261 "Exec=/opt/google/chrome/google-chrome %U\n",
262
263 "#!/usr/bin/env xdg-open\n"
264 "[Desktop Entry]\n"
265 "Name=GMail\n"
266 "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
267 "Icon=chrome-http__gmail.com\n"
268 #if !defined(USE_AURA)
269 // Aura Chrome does not (yet) set WMClass, so we only expect
270 // StartupWMClass on non-Aura builds.
271 "StartupWMClass=gmail.com\n"
272 #endif
273 },
274
275 // Make sure i18n-ed names and other fields are removed.
276 { "http://gmail.com",
277 "GMail",
278 "chrome-http__gmail.com",
279
280 "[Desktop Entry]\n"
281 "Name=Google Chrome\n"
282 "Name[en_AU]=Google Chrome\n"
283 "Name[pl]=Google Chrome\n"
284 "GenericName=Web Browser\n"
285 "GenericName[en_AU]=Web Browser\n"
286 "GenericName[pl]=Navegador Web\n"
287 "Exec=/opt/google/chrome/google-chrome %U\n"
288 "Comment[en_AU]=Some comment.\n"
289 "Comment[pl]=Jakis komentarz.\n",
290
291 "#!/usr/bin/env xdg-open\n"
292 "[Desktop Entry]\n"
293 "Name=GMail\n"
294 "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
295 "Icon=chrome-http__gmail.com\n"
296 #if !defined(USE_AURA)
297 // Aura Chrome does not (yet) set WMClass, so we only expect
298 // StartupWMClass on non-Aura builds.
299 "StartupWMClass=gmail.com\n"
300 #endif
301 },
302
303 // Make sure that empty icons are replaced by the chrome icon.
304 { "http://gmail.com",
305 "GMail",
306 "",
307
308 "[Desktop Entry]\n"
309 "Name=Google Chrome\n"
310 "Exec=/opt/google/chrome/google-chrome %U\n"
311 "Comment[pl]=Jakis komentarz.\n"
312 "Icon=/opt/google/chrome/product_logo_48.png\n",
313
314 "#!/usr/bin/env xdg-open\n"
315 "[Desktop Entry]\n"
316 "Name=GMail\n"
317 "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
318 "Icon=/opt/google/chrome/product_logo_48.png\n"
319 #if !defined(USE_AURA)
320 // Aura Chrome does not (yet) set WMClass, so we only expect
321 // StartupWMClass on non-Aura builds.
322 "StartupWMClass=gmail.com\n"
323 #endif
324 },
325
326 // Now we're starting to be more evil...
327 { "http://evil.com/evil --join-the-b0tnet",
328 "Ownz0red\nExec=rm -rf /",
329 "chrome-http__evil.com_evil",
330
331 "[Desktop Entry]\n"
332 "Name=Google Chrome\n"
333 "Exec=/opt/google/chrome/google-chrome %U\n",
334
335 "#!/usr/bin/env xdg-open\n"
336 "[Desktop Entry]\n"
337 "Name=http://evil.com/evil%20--join-the-b0tnet\n"
338 "Exec=/opt/google/chrome/google-chrome "
339 "--app=http://evil.com/evil%20--join-the-b0tnet\n"
340 "Icon=chrome-http__evil.com_evil\n"
341 #if !defined(USE_AURA)
342 // Aura Chrome does not (yet) set WMClass, so we only expect
343 // StartupWMClass on non-Aura builds.
344 "StartupWMClass=evil.com__evil%20--join-the-b0tnet\n"
345 #endif
346 },
347 { "http://evil.com/evil; rm -rf /; \"; rm -rf $HOME >ownz0red",
348 "Innocent Title",
349 "chrome-http__evil.com_evil",
350
351 "[Desktop Entry]\n"
352 "Name=Google Chrome\n"
353 "Exec=/opt/google/chrome/google-chrome %U\n",
354
355 "#!/usr/bin/env xdg-open\n"
356 "[Desktop Entry]\n"
357 "Name=Innocent Title\n"
358 "Exec=/opt/google/chrome/google-chrome "
359 "\"--app=http://evil.com/evil;%20rm%20-rf%20/;%20%22;%20rm%20"
360 // Note: $ is escaped as \$ within an arg to Exec, and then
361 // the \ is escaped as \\ as all strings in a Desktop file should
362 // be; finally, \\ becomes \\\\ when represented in a C++ string!
363 "-rf%20\\\\$HOME%20%3Eownz0red\"\n"
364 "Icon=chrome-http__evil.com_evil\n"
365 #if !defined(USE_AURA)
366 // Aura Chrome does not (yet) set WMClass, so we only expect
367 // StartupWMClass on non-Aura builds.
368 "StartupWMClass=evil.com__evil;%20rm%20-rf%20_;%20%22;%20"
369 "rm%20-rf%20$HOME%20%3Eownz0red\n"
370 #endif
371 },
372 { "http://evil.com/evil | cat `echo ownz0red` >/dev/null",
373 "Innocent Title",
374 "chrome-http__evil.com_evil",
375
376 "[Desktop Entry]\n"
377 "Name=Google Chrome\n"
378 "Exec=/opt/google/chrome/google-chrome %U\n",
379
380 "#!/usr/bin/env xdg-open\n"
381 "[Desktop Entry]\n"
382 "Name=Innocent Title\n"
383 "Exec=/opt/google/chrome/google-chrome "
384 "--app=http://evil.com/evil%20%7C%20cat%20%60echo%20ownz0red"
385 "%60%20%3E/dev/null\n"
386 "Icon=chrome-http__evil.com_evil\n"
387 #if !defined(USE_AURA)
388 // Aura Chrome does not (yet) set WMClass, so we only expect
389 // StartupWMClass on non-Aura builds.
390 "StartupWMClass=evil.com__evil%20%7C%20cat%20%60echo%20ownz0red"
391 "%60%20%3E_dev_null\n"
392 #endif
393 },
394 };
395
396 // Set the language to en_AU. This causes glib to copy the en_AU localized
397 // strings into the shortcut file. (We want to test that they are removed.)
398 ScopedEnvironment env;
399 env.Set("LC_ALL", "en_AU.UTF-8");
400 env.Set("LANGUAGE", "en_AU.UTF-8");
401
402 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); i++) {
403 SCOPED_TRACE(i);
404 EXPECT_EQ(
405 test_cases[i].expected_output,
406 ShellIntegrationLinux::GetDesktopFileContents(
407 test_cases[i].template_contents,
408 web_app::GenerateApplicationNameFromURL(GURL(test_cases[i].url)),
409 GURL(test_cases[i].url),
410 "",
411 base::FilePath(),
412 ASCIIToUTF16(test_cases[i].title),
413 test_cases[i].icon_name,
414 base::FilePath()));
415 }
416 }
417 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698