Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / shell_integration_linux_unittest.cc
1 // Copyright 2013 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_linux.h"
6
7 #include <algorithm>
8 #include <cstdlib>
9 #include <map>
10
11 #include "base/base_paths.h"
12 #include "base/command_line.h"
13 #include "base/environment.h"
14 #include "base/files/file_path.h"
15 #include "base/files/file_util.h"
16 #include "base/files/scoped_temp_dir.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/stl_util.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/test/scoped_path_override.h"
22 #include "chrome/common/chrome_constants.h"
23 #include "content/public/test/test_browser_thread.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "url/gurl.h"
27
28 #define FPL FILE_PATH_LITERAL
29
30 using content::BrowserThread;
31 using ::testing::ElementsAre;
32
33 namespace shell_integration_linux {
34
35 namespace {
36
37 // Provides mock environment variables values based on a stored map.
38 class MockEnvironment : public base::Environment {
39  public:
40   MockEnvironment() {}
41
42   void Set(const std::string& name, const std::string& value) {
43     variables_[name] = value;
44   }
45
46   virtual bool GetVar(const char* variable_name, std::string* result) OVERRIDE {
47     if (ContainsKey(variables_, variable_name)) {
48       *result = variables_[variable_name];
49       return true;
50     }
51
52     return false;
53   }
54
55   virtual bool SetVar(const char* variable_name,
56                       const std::string& new_value) OVERRIDE {
57     ADD_FAILURE();
58     return false;
59   }
60
61   virtual bool UnSetVar(const char* variable_name) OVERRIDE {
62     ADD_FAILURE();
63     return false;
64   }
65
66  private:
67   std::map<std::string, std::string> variables_;
68
69   DISALLOW_COPY_AND_ASSIGN(MockEnvironment);
70 };
71
72 }  // namespace
73
74 TEST(ShellIntegrationTest, GetDataWriteLocation) {
75   base::MessageLoop message_loop;
76   content::TestBrowserThread file_thread(BrowserThread::FILE, &message_loop);
77
78   // Test that it returns $XDG_DATA_HOME.
79   {
80     MockEnvironment env;
81     env.Set("HOME", "/home/user");
82     env.Set("XDG_DATA_HOME", "/user/path");
83     base::FilePath path;
84     ASSERT_TRUE(GetDataWriteLocation(&env, &path));
85     EXPECT_EQ(base::FilePath("/user/path"), path);
86   }
87
88   // Test that $XDG_DATA_HOME falls back to $HOME/.local/share.
89   {
90     MockEnvironment env;
91     env.Set("HOME", "/home/user");
92     base::FilePath path;
93     ASSERT_TRUE(GetDataWriteLocation(&env, &path));
94     EXPECT_EQ(base::FilePath("/home/user/.local/share"), path);
95   }
96
97   // Test that if neither $XDG_DATA_HOME nor $HOME are specified, it fails.
98   {
99     MockEnvironment env;
100     base::FilePath path;
101     ASSERT_FALSE(GetDataWriteLocation(&env, &path));
102   }
103 }
104
105 TEST(ShellIntegrationTest, GetDataSearchLocations) {
106   base::MessageLoop message_loop;
107   content::TestBrowserThread file_thread(BrowserThread::FILE, &message_loop);
108
109   // Test that it returns $XDG_DATA_HOME + $XDG_DATA_DIRS.
110   {
111     MockEnvironment env;
112     env.Set("HOME", "/home/user");
113     env.Set("XDG_DATA_HOME", "/user/path");
114     env.Set("XDG_DATA_DIRS", "/system/path/1:/system/path/2");
115     EXPECT_THAT(
116         GetDataSearchLocations(&env),
117         ElementsAre(base::FilePath("/user/path"),
118                     base::FilePath("/system/path/1"),
119                     base::FilePath("/system/path/2")));
120   }
121
122   // Test that $XDG_DATA_HOME falls back to $HOME/.local/share.
123   {
124     MockEnvironment env;
125     env.Set("HOME", "/home/user");
126     env.Set("XDG_DATA_DIRS", "/system/path/1:/system/path/2");
127     EXPECT_THAT(
128         GetDataSearchLocations(&env),
129         ElementsAre(base::FilePath("/home/user/.local/share"),
130                     base::FilePath("/system/path/1"),
131                     base::FilePath("/system/path/2")));
132   }
133
134   // Test that if neither $XDG_DATA_HOME nor $HOME are specified, it still
135   // succeeds.
136   {
137     MockEnvironment env;
138     env.Set("XDG_DATA_DIRS", "/system/path/1:/system/path/2");
139     EXPECT_THAT(
140         GetDataSearchLocations(&env),
141         ElementsAre(base::FilePath("/system/path/1"),
142                     base::FilePath("/system/path/2")));
143   }
144
145   // Test that $XDG_DATA_DIRS falls back to the two default paths.
146   {
147     MockEnvironment env;
148     env.Set("HOME", "/home/user");
149     env.Set("XDG_DATA_HOME", "/user/path");
150     EXPECT_THAT(
151         GetDataSearchLocations(&env),
152         ElementsAre(base::FilePath("/user/path"),
153                     base::FilePath("/usr/local/share"),
154                     base::FilePath("/usr/share")));
155   }
156 }
157
158 TEST(ShellIntegrationTest, GetExistingShortcutLocations) {
159   base::FilePath kProfilePath("Profile 1");
160   const char kExtensionId[] = "test_extension";
161   const char kTemplateFilename[] = "chrome-test_extension-Profile_1.desktop";
162   base::FilePath kTemplateFilepath(kTemplateFilename);
163   const char kNoDisplayDesktopFile[] = "[Desktop Entry]\nNoDisplay=true";
164
165   base::MessageLoop message_loop;
166   content::TestBrowserThread file_thread(BrowserThread::FILE, &message_loop);
167
168   // No existing shortcuts.
169   {
170     MockEnvironment env;
171     web_app::ShortcutLocations result =
172         GetExistingShortcutLocations(&env, kProfilePath, kExtensionId);
173     EXPECT_FALSE(result.on_desktop);
174     EXPECT_EQ(web_app::APP_MENU_LOCATION_NONE,
175               result.applications_menu_location);
176
177     EXPECT_FALSE(result.in_quick_launch_bar);
178   }
179
180   // Shortcut on desktop.
181   {
182     base::ScopedTempDir temp_dir;
183     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
184     base::FilePath desktop_path = temp_dir.path();
185
186     MockEnvironment env;
187     ASSERT_TRUE(base::CreateDirectory(desktop_path));
188     ASSERT_FALSE(base::WriteFile(
189         desktop_path.AppendASCII(kTemplateFilename),
190         "", 0));
191     web_app::ShortcutLocations result = GetExistingShortcutLocations(
192         &env, kProfilePath, kExtensionId, desktop_path);
193     EXPECT_TRUE(result.on_desktop);
194     EXPECT_EQ(web_app::APP_MENU_LOCATION_NONE,
195               result.applications_menu_location);
196
197     EXPECT_FALSE(result.in_quick_launch_bar);
198   }
199
200   // Shortcut in applications directory.
201   {
202     base::ScopedTempDir temp_dir;
203     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
204     base::FilePath apps_path = temp_dir.path().AppendASCII("applications");
205
206     MockEnvironment env;
207     env.Set("XDG_DATA_HOME", temp_dir.path().value());
208     ASSERT_TRUE(base::CreateDirectory(apps_path));
209     ASSERT_FALSE(base::WriteFile(
210         apps_path.AppendASCII(kTemplateFilename),
211         "", 0));
212     web_app::ShortcutLocations result =
213         GetExistingShortcutLocations(&env, kProfilePath, kExtensionId);
214     EXPECT_FALSE(result.on_desktop);
215     EXPECT_EQ(web_app::APP_MENU_LOCATION_SUBDIR_CHROMEAPPS,
216               result.applications_menu_location);
217
218     EXPECT_FALSE(result.in_quick_launch_bar);
219   }
220
221   // Shortcut in applications directory with NoDisplay=true.
222   {
223     base::ScopedTempDir temp_dir;
224     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
225     base::FilePath apps_path = temp_dir.path().AppendASCII("applications");
226
227     MockEnvironment env;
228     env.Set("XDG_DATA_HOME", temp_dir.path().value());
229     ASSERT_TRUE(base::CreateDirectory(apps_path));
230     ASSERT_TRUE(base::WriteFile(
231         apps_path.AppendASCII(kTemplateFilename),
232         kNoDisplayDesktopFile, strlen(kNoDisplayDesktopFile)));
233     web_app::ShortcutLocations result =
234         GetExistingShortcutLocations(&env, kProfilePath, kExtensionId);
235     // Doesn't count as being in applications menu.
236     EXPECT_FALSE(result.on_desktop);
237     EXPECT_EQ(web_app::APP_MENU_LOCATION_HIDDEN,
238               result.applications_menu_location);
239     EXPECT_FALSE(result.in_quick_launch_bar);
240   }
241
242   // Shortcut on desktop and in applications directory.
243   {
244     base::ScopedTempDir temp_dir1;
245     ASSERT_TRUE(temp_dir1.CreateUniqueTempDir());
246     base::FilePath desktop_path = temp_dir1.path();
247
248     base::ScopedTempDir temp_dir2;
249     ASSERT_TRUE(temp_dir2.CreateUniqueTempDir());
250     base::FilePath apps_path = temp_dir2.path().AppendASCII("applications");
251
252     MockEnvironment env;
253     ASSERT_TRUE(base::CreateDirectory(desktop_path));
254     ASSERT_FALSE(base::WriteFile(
255         desktop_path.AppendASCII(kTemplateFilename),
256         "", 0));
257     env.Set("XDG_DATA_HOME", temp_dir2.path().value());
258     ASSERT_TRUE(base::CreateDirectory(apps_path));
259     ASSERT_FALSE(base::WriteFile(
260         apps_path.AppendASCII(kTemplateFilename),
261         "", 0));
262     web_app::ShortcutLocations result = GetExistingShortcutLocations(
263         &env, kProfilePath, kExtensionId, desktop_path);
264     EXPECT_TRUE(result.on_desktop);
265     EXPECT_EQ(web_app::APP_MENU_LOCATION_SUBDIR_CHROMEAPPS,
266               result.applications_menu_location);
267     EXPECT_FALSE(result.in_quick_launch_bar);
268   }
269 }
270
271 TEST(ShellIntegrationTest, GetExistingShortcutContents) {
272   const char kTemplateFilename[] = "shortcut-test.desktop";
273   base::FilePath kTemplateFilepath(kTemplateFilename);
274   const char kTestData1[] = "a magical testing string";
275   const char kTestData2[] = "a different testing string";
276
277   base::MessageLoop message_loop;
278   content::TestBrowserThread file_thread(BrowserThread::FILE, &message_loop);
279
280   // Test that it searches $XDG_DATA_HOME/applications.
281   {
282     base::ScopedTempDir temp_dir;
283     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
284
285     MockEnvironment env;
286     env.Set("XDG_DATA_HOME", temp_dir.path().value());
287     // Create a file in a non-applications directory. This should be ignored.
288     ASSERT_TRUE(base::WriteFile(
289         temp_dir.path().AppendASCII(kTemplateFilename),
290         kTestData2, strlen(kTestData2)));
291     ASSERT_TRUE(base::CreateDirectory(
292         temp_dir.path().AppendASCII("applications")));
293     ASSERT_TRUE(base::WriteFile(
294         temp_dir.path().AppendASCII("applications")
295             .AppendASCII(kTemplateFilename),
296         kTestData1, strlen(kTestData1)));
297     std::string contents;
298     ASSERT_TRUE(
299         GetExistingShortcutContents(&env, kTemplateFilepath, &contents));
300     EXPECT_EQ(kTestData1, contents);
301   }
302
303   // Test that it falls back to $HOME/.local/share/applications.
304   {
305     base::ScopedTempDir temp_dir;
306     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
307
308     MockEnvironment env;
309     env.Set("HOME", temp_dir.path().value());
310     ASSERT_TRUE(base::CreateDirectory(
311         temp_dir.path().AppendASCII(".local/share/applications")));
312     ASSERT_TRUE(base::WriteFile(
313         temp_dir.path().AppendASCII(".local/share/applications")
314             .AppendASCII(kTemplateFilename),
315         kTestData1, strlen(kTestData1)));
316     std::string contents;
317     ASSERT_TRUE(
318         GetExistingShortcutContents(&env, kTemplateFilepath, &contents));
319     EXPECT_EQ(kTestData1, contents);
320   }
321
322   // Test that it searches $XDG_DATA_DIRS/applications.
323   {
324     base::ScopedTempDir temp_dir;
325     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
326
327     MockEnvironment env;
328     env.Set("XDG_DATA_DIRS", temp_dir.path().value());
329     ASSERT_TRUE(base::CreateDirectory(
330         temp_dir.path().AppendASCII("applications")));
331     ASSERT_TRUE(base::WriteFile(
332         temp_dir.path().AppendASCII("applications")
333             .AppendASCII(kTemplateFilename),
334         kTestData2, strlen(kTestData2)));
335     std::string contents;
336     ASSERT_TRUE(
337         GetExistingShortcutContents(&env, kTemplateFilepath, &contents));
338     EXPECT_EQ(kTestData2, contents);
339   }
340
341   // Test that it searches $X/applications for each X in $XDG_DATA_DIRS.
342   {
343     base::ScopedTempDir temp_dir1;
344     ASSERT_TRUE(temp_dir1.CreateUniqueTempDir());
345     base::ScopedTempDir temp_dir2;
346     ASSERT_TRUE(temp_dir2.CreateUniqueTempDir());
347
348     MockEnvironment env;
349     env.Set("XDG_DATA_DIRS", temp_dir1.path().value() + ":" +
350                              temp_dir2.path().value());
351     // Create a file in a non-applications directory. This should be ignored.
352     ASSERT_TRUE(base::WriteFile(
353         temp_dir1.path().AppendASCII(kTemplateFilename),
354         kTestData1, strlen(kTestData1)));
355     // Only create a findable desktop file in the second path.
356     ASSERT_TRUE(base::CreateDirectory(
357         temp_dir2.path().AppendASCII("applications")));
358     ASSERT_TRUE(base::WriteFile(
359         temp_dir2.path().AppendASCII("applications")
360             .AppendASCII(kTemplateFilename),
361         kTestData2, strlen(kTestData2)));
362     std::string contents;
363     ASSERT_TRUE(
364         GetExistingShortcutContents(&env, kTemplateFilepath, &contents));
365     EXPECT_EQ(kTestData2, contents);
366   }
367 }
368
369 TEST(ShellIntegrationTest, GetExtensionShortcutFilename) {
370   base::FilePath kProfilePath("a/b/c/Profile Name?");
371   const char kExtensionId[] = "extensionid";
372   EXPECT_EQ(base::FilePath("chrome-extensionid-Profile_Name_.desktop"),
373             GetExtensionShortcutFilename(kProfilePath, kExtensionId));
374 }
375
376 TEST(ShellIntegrationTest, GetExistingProfileShortcutFilenames) {
377   base::FilePath kProfilePath("a/b/c/Profile Name?");
378   const char kApp1Filename[] = "chrome-extension1-Profile_Name_.desktop";
379   const char kApp2Filename[] = "chrome-extension2-Profile_Name_.desktop";
380   const char kUnrelatedAppFilename[] = "chrome-extension-Other_Profile.desktop";
381
382   base::MessageLoop message_loop;
383   content::TestBrowserThread file_thread(BrowserThread::FILE, &message_loop);
384
385   base::ScopedTempDir temp_dir;
386   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
387   ASSERT_EQ(0,
388             base::WriteFile(
389                 temp_dir.path().AppendASCII(kApp1Filename), "", 0));
390   ASSERT_EQ(0,
391             base::WriteFile(
392                 temp_dir.path().AppendASCII(kApp2Filename), "", 0));
393   // This file should not be returned in the results.
394   ASSERT_EQ(0,
395             base::WriteFile(
396                 temp_dir.path().AppendASCII(kUnrelatedAppFilename), "", 0));
397   std::vector<base::FilePath> paths =
398       GetExistingProfileShortcutFilenames(kProfilePath, temp_dir.path());
399   // Path order is arbitrary. Sort the output for consistency.
400   std::sort(paths.begin(), paths.end());
401   EXPECT_THAT(paths,
402               ElementsAre(base::FilePath(kApp1Filename),
403                           base::FilePath(kApp2Filename)));
404 }
405
406 TEST(ShellIntegrationTest, GetWebShortcutFilename) {
407   const struct {
408     const base::FilePath::CharType* path;
409     const char* url;
410   } test_cases[] = {
411     { FPL("http___foo_.desktop"), "http://foo" },
412     { FPL("http___foo_bar_.desktop"), "http://foo/bar/" },
413     { FPL("http___foo_bar_a=b&c=d.desktop"), "http://foo/bar?a=b&c=d" },
414
415     // Now we're starting to be more evil...
416     { FPL("http___foo_.desktop"), "http://foo/bar/baz/../../../../../" },
417     { FPL("http___foo_.desktop"), "http://foo/bar/././../baz/././../" },
418     { FPL("http___.._.desktop"), "http://../../../../" },
419   };
420   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); i++) {
421     EXPECT_EQ(std::string(chrome::kBrowserProcessExecutableName) + "-" +
422               test_cases[i].path,
423               GetWebShortcutFilename(GURL(test_cases[i].url)).value()) <<
424         " while testing " << test_cases[i].url;
425   }
426 }
427
428 TEST(ShellIntegrationTest, GetDesktopFileContents) {
429   const base::FilePath kChromeExePath("/opt/google/chrome/google-chrome");
430   const struct {
431     const char* url;
432     const char* title;
433     const char* icon_name;
434     const char* categories;
435     bool nodisplay;
436     const char* expected_output;
437   } test_cases[] = {
438     // Real-world case.
439     { "http://gmail.com",
440       "GMail",
441       "chrome-http__gmail.com",
442       "",
443       false,
444
445       "#!/usr/bin/env xdg-open\n"
446       "[Desktop Entry]\n"
447       "Version=1.0\n"
448       "Terminal=false\n"
449       "Type=Application\n"
450       "Name=GMail\n"
451       "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
452       "Icon=chrome-http__gmail.com\n"
453       "StartupWMClass=gmail.com\n"
454     },
455
456     // Make sure that empty icons are replaced by the chrome icon.
457     { "http://gmail.com",
458       "GMail",
459       "",
460       "",
461       false,
462
463       "#!/usr/bin/env xdg-open\n"
464       "[Desktop Entry]\n"
465       "Version=1.0\n"
466       "Terminal=false\n"
467       "Type=Application\n"
468       "Name=GMail\n"
469       "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
470 #if defined(GOOGLE_CHROME_BUILD)
471       "Icon=google-chrome\n"
472 #else
473       "Icon=chromium-browser\n"
474 #endif
475       "StartupWMClass=gmail.com\n"
476     },
477
478     // Test adding categories and NoDisplay=true.
479     { "http://gmail.com",
480       "GMail",
481       "chrome-http__gmail.com",
482       "Graphics;Education;",
483       true,
484
485       "#!/usr/bin/env xdg-open\n"
486       "[Desktop Entry]\n"
487       "Version=1.0\n"
488       "Terminal=false\n"
489       "Type=Application\n"
490       "Name=GMail\n"
491       "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n"
492       "Icon=chrome-http__gmail.com\n"
493       "Categories=Graphics;Education;\n"
494       "NoDisplay=true\n"
495       "StartupWMClass=gmail.com\n"
496     },
497
498     // Now we're starting to be more evil...
499     { "http://evil.com/evil --join-the-b0tnet",
500       "Ownz0red\nExec=rm -rf /",
501       "chrome-http__evil.com_evil",
502       "",
503       false,
504
505       "#!/usr/bin/env xdg-open\n"
506       "[Desktop Entry]\n"
507       "Version=1.0\n"
508       "Terminal=false\n"
509       "Type=Application\n"
510       "Name=http://evil.com/evil%20--join-the-b0tnet\n"
511       "Exec=/opt/google/chrome/google-chrome "
512       "--app=http://evil.com/evil%20--join-the-b0tnet\n"
513       "Icon=chrome-http__evil.com_evil\n"
514       "StartupWMClass=evil.com__evil%20--join-the-b0tnet\n"
515     },
516     { "http://evil.com/evil; rm -rf /; \"; rm -rf $HOME >ownz0red",
517       "Innocent Title",
518       "chrome-http__evil.com_evil",
519       "",
520       false,
521
522       "#!/usr/bin/env xdg-open\n"
523       "[Desktop Entry]\n"
524       "Version=1.0\n"
525       "Terminal=false\n"
526       "Type=Application\n"
527       "Name=Innocent Title\n"
528       "Exec=/opt/google/chrome/google-chrome "
529       "\"--app=http://evil.com/evil;%20rm%20-rf%20/;%20%22;%20rm%20"
530       // Note: $ is escaped as \$ within an arg to Exec, and then
531       // the \ is escaped as \\ as all strings in a Desktop file should
532       // be; finally, \\ becomes \\\\ when represented in a C++ string!
533       "-rf%20\\\\$HOME%20%3Eownz0red\"\n"
534       "Icon=chrome-http__evil.com_evil\n"
535       "StartupWMClass=evil.com__evil;%20rm%20-rf%20_;%20%22;%20"
536       "rm%20-rf%20$HOME%20%3Eownz0red\n"
537     },
538     { "http://evil.com/evil | cat `echo ownz0red` >/dev/null",
539       "Innocent Title",
540       "chrome-http__evil.com_evil",
541       "",
542       false,
543
544       "#!/usr/bin/env xdg-open\n"
545       "[Desktop Entry]\n"
546       "Version=1.0\n"
547       "Terminal=false\n"
548       "Type=Application\n"
549       "Name=Innocent Title\n"
550       "Exec=/opt/google/chrome/google-chrome "
551       "--app=http://evil.com/evil%20%7C%20cat%20%60echo%20ownz0red"
552       "%60%20%3E/dev/null\n"
553       "Icon=chrome-http__evil.com_evil\n"
554       "StartupWMClass=evil.com__evil%20%7C%20cat%20%60echo%20ownz0red"
555       "%60%20%3E_dev_null\n"
556     },
557   };
558
559   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); i++) {
560     SCOPED_TRACE(i);
561     EXPECT_EQ(
562         test_cases[i].expected_output,
563         GetDesktopFileContents(
564             kChromeExePath,
565             web_app::GenerateApplicationNameFromURL(GURL(test_cases[i].url)),
566             GURL(test_cases[i].url),
567             std::string(),
568             base::ASCIIToUTF16(test_cases[i].title),
569             test_cases[i].icon_name,
570             base::FilePath(),
571             test_cases[i].categories,
572             test_cases[i].nodisplay));
573   }
574 }
575
576 TEST(ShellIntegrationTest, GetDesktopFileContentsAppList) {
577   const base::FilePath kChromeExePath("/opt/google/chrome/google-chrome");
578   base::CommandLine command_line(kChromeExePath);
579   command_line.AppendSwitch("--show-app-list");
580   EXPECT_EQ(
581       "#!/usr/bin/env xdg-open\n"
582       "[Desktop Entry]\n"
583       "Version=1.0\n"
584       "Terminal=false\n"
585       "Type=Application\n"
586       "Name=Chrome App Launcher\n"
587       "Exec=/opt/google/chrome/google-chrome --show-app-list\n"
588       "Icon=chrome_app_list\n"
589       "Categories=Network;WebBrowser;\n"
590       "StartupWMClass=chrome-app-list\n",
591       GetDesktopFileContentsForCommand(
592           command_line,
593           "chrome-app-list",
594           GURL(),
595           base::ASCIIToUTF16("Chrome App Launcher"),
596           "chrome_app_list",
597           "Network;WebBrowser;",
598           false));
599 }
600
601 TEST(ShellIntegrationTest, GetDirectoryFileContents) {
602   const struct {
603     const char* title;
604     const char* icon_name;
605     const char* expected_output;
606   } test_cases[] = {
607     // Real-world case.
608     { "Chrome Apps",
609       "chrome-apps",
610
611       "[Desktop Entry]\n"
612       "Version=1.0\n"
613       "Type=Directory\n"
614       "Name=Chrome Apps\n"
615       "Icon=chrome-apps\n"
616     },
617
618     // Make sure that empty icons are replaced by the chrome icon.
619     { "Chrome Apps",
620       "",
621
622       "[Desktop Entry]\n"
623       "Version=1.0\n"
624       "Type=Directory\n"
625       "Name=Chrome Apps\n"
626 #if defined(GOOGLE_CHROME_BUILD)
627       "Icon=google-chrome\n"
628 #else
629       "Icon=chromium-browser\n"
630 #endif
631     },
632   };
633
634   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); i++) {
635     SCOPED_TRACE(i);
636     EXPECT_EQ(test_cases[i].expected_output,
637               GetDirectoryFileContents(base::ASCIIToUTF16(test_cases[i].title),
638                                        test_cases[i].icon_name));
639   }
640 }
641
642 }  // namespace shell_integration_linux