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