// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/installer/util/shell_util.h" #include <vector> #include "base/base_paths.h" #include "base/base_paths_win.h" #include "base/file_util.h" #include "base/files/file_enumerator.h" #include "base/files/scoped_temp_dir.h" #include "base/md5.h" #include "base/memory/scoped_ptr.h" #include "base/strings/string16.h" #include "base/strings/string_util.h" #include "base/test/scoped_path_override.h" #include "base/test/test_shortcut_win.h" #include "base/win/shortcut.h" #include "base/win/windows_version.h" #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/product.h" #include "chrome/installer/util/util_constants.h" #include "testing/gtest/include/gtest/gtest.h" namespace { const wchar_t kManganeseExe[] = L"manganese.exe"; // TODO(huangs): Separate this into generic shortcut tests and Chrome-specific // tests. Specifically, we should not overly rely on getting shortcut properties // from product_->AddDefaultShortcutProperties(). class ShellUtilShortcutTest : public testing::Test { protected: ShellUtilShortcutTest() : test_properties_(ShellUtil::CURRENT_USER) {} virtual void SetUp() OVERRIDE { dist_ = BrowserDistribution::GetDistribution(); ASSERT_TRUE(dist_ != NULL); product_.reset(new installer::Product(dist_)); ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); chrome_exe_ = temp_dir_.path().Append(installer::kChromeExe); EXPECT_EQ(0, file_util::WriteFile(chrome_exe_, "", 0)); manganese_exe_ = temp_dir_.path().Append(kManganeseExe); EXPECT_EQ(0, file_util::WriteFile(manganese_exe_, "", 0)); ASSERT_TRUE(fake_user_desktop_.CreateUniqueTempDir()); ASSERT_TRUE(fake_common_desktop_.CreateUniqueTempDir()); ASSERT_TRUE(fake_user_quick_launch_.CreateUniqueTempDir()); ASSERT_TRUE(fake_default_user_quick_launch_.CreateUniqueTempDir()); ASSERT_TRUE(fake_start_menu_.CreateUniqueTempDir()); ASSERT_TRUE(fake_common_start_menu_.CreateUniqueTempDir()); user_desktop_override_.reset( new base::ScopedPathOverride(base::DIR_USER_DESKTOP, fake_user_desktop_.path())); common_desktop_override_.reset( new base::ScopedPathOverride(base::DIR_COMMON_DESKTOP, fake_common_desktop_.path())); user_quick_launch_override_.reset( new base::ScopedPathOverride(base::DIR_USER_QUICK_LAUNCH, fake_user_quick_launch_.path())); default_user_quick_launch_override_.reset( new base::ScopedPathOverride(base::DIR_DEFAULT_USER_QUICK_LAUNCH, fake_default_user_quick_launch_.path())); start_menu_override_.reset( new base::ScopedPathOverride(base::DIR_START_MENU, fake_start_menu_.path())); common_start_menu_override_.reset( new base::ScopedPathOverride(base::DIR_COMMON_START_MENU, fake_common_start_menu_.path())); base::FilePath icon_path; base::CreateTemporaryFileInDir(temp_dir_.path(), &icon_path); test_properties_.set_target(chrome_exe_); test_properties_.set_arguments(L"--test --chrome"); test_properties_.set_description(L"Makes polar bears dance."); test_properties_.set_icon(icon_path, 0); test_properties_.set_app_id(L"Polar.Bear"); test_properties_.set_dual_mode(true); } // Validates that the shortcut at |location| matches |properties| (and // implicit default properties) for |dist|. // Note: This method doesn't verify the |pin_to_taskbar| property as it // implies real (non-mocked) state which is flaky to test. void ValidateChromeShortcut( ShellUtil::ShortcutLocation location, BrowserDistribution* dist, const ShellUtil::ShortcutProperties& properties) { base::FilePath expected_path; switch (location) { case ShellUtil::SHORTCUT_LOCATION_DESKTOP: expected_path = (properties.level == ShellUtil::CURRENT_USER) ? fake_user_desktop_.path() : fake_common_desktop_.path(); break; case ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH: expected_path = (properties.level == ShellUtil::CURRENT_USER) ? fake_user_quick_launch_.path() : fake_default_user_quick_launch_.path(); break; case ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR: expected_path = (properties.level == ShellUtil::CURRENT_USER) ? fake_start_menu_.path() : fake_common_start_menu_.path(); expected_path = expected_path.Append( dist_->GetStartMenuShortcutSubfolder( BrowserDistribution::SUBFOLDER_CHROME)); break; default: ADD_FAILURE() << "Unknown location"; return; } string16 shortcut_name; if (properties.has_shortcut_name()) { shortcut_name = properties.shortcut_name; } else { shortcut_name = dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME); } shortcut_name.append(installer::kLnkExt); expected_path = expected_path.Append(shortcut_name); base::win::ShortcutProperties expected_properties; if (properties.has_target()) { expected_properties.set_target(properties.target); expected_properties.set_working_dir(properties.target.DirName()); } else { expected_properties.set_target(chrome_exe_); expected_properties.set_working_dir(chrome_exe_.DirName()); } if (properties.has_arguments()) expected_properties.set_arguments(properties.arguments); else expected_properties.set_arguments(string16()); if (properties.has_description()) expected_properties.set_description(properties.description); else expected_properties.set_description(dist->GetAppDescription()); if (properties.has_icon()) { expected_properties.set_icon(properties.icon, 0); } else { int icon_index = dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME); expected_properties.set_icon(chrome_exe_, icon_index); } if (properties.has_app_id()) { expected_properties.set_app_id(properties.app_id); } else { // Tests are always seen as user-level installs in ShellUtil. expected_properties.set_app_id(ShellUtil::GetBrowserModelId(dist, true)); } if (properties.has_dual_mode()) expected_properties.set_dual_mode(properties.dual_mode); else expected_properties.set_dual_mode(false); base::win::ValidateShortcut(expected_path, expected_properties); } BrowserDistribution* dist_; scoped_ptr<installer::Product> product_; // A ShellUtil::ShortcutProperties object with common properties set already. ShellUtil::ShortcutProperties test_properties_; base::ScopedTempDir temp_dir_; base::ScopedTempDir fake_user_desktop_; base::ScopedTempDir fake_common_desktop_; base::ScopedTempDir fake_user_quick_launch_; base::ScopedTempDir fake_default_user_quick_launch_; base::ScopedTempDir fake_start_menu_; base::ScopedTempDir fake_common_start_menu_; scoped_ptr<base::ScopedPathOverride> user_desktop_override_; scoped_ptr<base::ScopedPathOverride> common_desktop_override_; scoped_ptr<base::ScopedPathOverride> user_quick_launch_override_; scoped_ptr<base::ScopedPathOverride> default_user_quick_launch_override_; scoped_ptr<base::ScopedPathOverride> start_menu_override_; scoped_ptr<base::ScopedPathOverride> common_start_menu_override_; base::FilePath chrome_exe_; base::FilePath manganese_exe_; }; } // namespace TEST_F(ShellUtilShortcutTest, GetShortcutPath) { base::FilePath path; ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER, &path); EXPECT_EQ(fake_user_desktop_.path(), path); ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::SYSTEM_LEVEL, &path); EXPECT_EQ(fake_common_desktop_.path(), path); ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_, ShellUtil::CURRENT_USER, &path); EXPECT_EQ(fake_user_quick_launch_.path(), path); ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_, ShellUtil::SYSTEM_LEVEL, &path); EXPECT_EQ(fake_default_user_quick_launch_.path(), path); string16 start_menu_subfolder = dist_->GetStartMenuShortcutSubfolder( BrowserDistribution::SUBFOLDER_CHROME); ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_, ShellUtil::CURRENT_USER, &path); EXPECT_EQ(fake_start_menu_.path().Append(start_menu_subfolder), path); ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_, ShellUtil::SYSTEM_LEVEL, &path); EXPECT_EQ(fake_common_start_menu_.path().Append(start_menu_subfolder), path); } TEST_F(ShellUtilShortcutTest, CreateChromeExeShortcutWithDefaultProperties) { ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER); product_->AddDefaultShortcutProperties(chrome_exe_, &properties); ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, properties, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, properties); } TEST_F(ShellUtilShortcutTest, CreateStartMenuShortcutWithAllProperties) { test_properties_.set_shortcut_name(L"Bobo le shortcut"); test_properties_.level = ShellUtil::SYSTEM_LEVEL; ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_, test_properties_); } TEST_F(ShellUtilShortcutTest, ReplaceSystemLevelQuickLaunchShortcut) { test_properties_.level = ShellUtil::SYSTEM_LEVEL; ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); ShellUtil::ShortcutProperties new_properties(ShellUtil::SYSTEM_LEVEL); product_->AddDefaultShortcutProperties(chrome_exe_, &new_properties); new_properties.set_description(L"New description"); new_properties.set_arguments(L"--new-arguments"); ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_, new_properties, ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING)); // Expect the properties set in |new_properties| to be set as above and // properties that don't have a default value to be set back to their default // (as validated in ValidateChromeShortcut()) or unset if they don't . ShellUtil::ShortcutProperties expected_properties(new_properties); expected_properties.set_dual_mode(false); ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_, expected_properties); } TEST_F(ShellUtilShortcutTest, UpdateQuickLaunchShortcutArguments) { ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); // Only changing one property, don't need all the defaults. ShellUtil::ShortcutProperties updated_properties(ShellUtil::CURRENT_USER); updated_properties.set_arguments(L"--updated --arguments"); ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_, updated_properties, ShellUtil::SHELL_SHORTCUT_UPDATE_EXISTING)); // Expect the properties set in |updated_properties| to be set as above and // all other properties to remain unchanged. ShellUtil::ShortcutProperties expected_properties(test_properties_); expected_properties.set_arguments(updated_properties.arguments); ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_, expected_properties); } TEST_F(ShellUtilShortcutTest, UpdateAddDualModeToStartMenuShortcut) { ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER); product_->AddDefaultShortcutProperties(chrome_exe_, &properties); ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_, properties, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); ShellUtil::ShortcutProperties added_properties(ShellUtil::CURRENT_USER); added_properties.set_dual_mode(true); ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_, added_properties, ShellUtil::SHELL_SHORTCUT_UPDATE_EXISTING)); ShellUtil::ShortcutProperties expected_properties(properties); expected_properties.set_dual_mode(true); ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_, expected_properties); } TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevel) { ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL)); ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_); } TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevelWithSystemLevelPresent) { string16 shortcut_name( dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) + installer::kLnkExt); test_properties_.level = ShellUtil::SYSTEM_LEVEL; ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); ASSERT_TRUE(base::PathExists( fake_common_desktop_.path().Append(shortcut_name))); test_properties_.level = ShellUtil::CURRENT_USER; ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL)); ASSERT_FALSE(base::PathExists( fake_user_desktop_.path().Append(shortcut_name))); } TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevelStartMenu) { ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL)); ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_, test_properties_); } TEST_F(ShellUtilShortcutTest, CreateAlwaysUserWithSystemLevelPresent) { string16 shortcut_name( dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) + installer::kLnkExt); test_properties_.level = ShellUtil::SYSTEM_LEVEL; ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); ASSERT_TRUE(base::PathExists( fake_common_desktop_.path().Append(shortcut_name))); test_properties_.level = ShellUtil::CURRENT_USER; ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); ASSERT_TRUE(base::PathExists( fake_user_desktop_.path().Append(shortcut_name))); } TEST_F(ShellUtilShortcutTest, RemoveChromeShortcut) { ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); string16 shortcut_name( dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) + installer::kLnkExt); base::FilePath shortcut_path(fake_user_desktop_.path().Append(shortcut_name)); ASSERT_TRUE(base::PathExists(shortcut_path)); ASSERT_TRUE(ShellUtil::RemoveShortcuts( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER, chrome_exe_)); ASSERT_FALSE(base::PathExists(shortcut_path)); ASSERT_TRUE(base::PathExists(shortcut_path.DirName())); } TEST_F(ShellUtilShortcutTest, RemoveSystemLevelChromeShortcut) { test_properties_.level = ShellUtil::SYSTEM_LEVEL; ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); string16 shortcut_name( dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) + installer::kLnkExt); base::FilePath shortcut_path( fake_common_desktop_.path().Append(shortcut_name)); ASSERT_TRUE(base::PathExists(shortcut_path)); ASSERT_TRUE(ShellUtil::RemoveShortcuts( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::SYSTEM_LEVEL, chrome_exe_)); ASSERT_FALSE(base::PathExists(shortcut_path)); ASSERT_TRUE(base::PathExists(shortcut_path.DirName())); } TEST_F(ShellUtilShortcutTest, RemoveMultipleChromeShortcuts) { const wchar_t kShortcutName1[] = L"Chrome 1"; const wchar_t kShortcutName2[] = L"Chrome 2"; test_properties_.set_shortcut_name(kShortcutName1); ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); string16 shortcut1_name( string16(kShortcutName1).append(installer::kLnkExt)); base::FilePath shortcut1_path( fake_user_desktop_.path().Append(shortcut1_name)); ASSERT_TRUE(base::PathExists(shortcut1_path)); test_properties_.set_shortcut_name(kShortcutName2); test_properties_.set_arguments(L"--profile-directory=\"Profile 2\""); ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); string16 shortcut2_name(string16(kShortcutName2).append(installer::kLnkExt)); base::FilePath shortcut2_path( fake_user_desktop_.path().Append(shortcut2_name)); ASSERT_TRUE(base::PathExists(shortcut2_path)); ASSERT_TRUE(ShellUtil::RemoveShortcuts( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER, chrome_exe_)); ASSERT_FALSE(base::PathExists(shortcut1_path)); ASSERT_FALSE(base::PathExists(shortcut2_path)); ASSERT_TRUE(base::PathExists(shortcut1_path.DirName())); } TEST_F(ShellUtilShortcutTest, UpdateChromeShortcutsWithArgs) { ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); string16 shortcut_name( dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) + installer::kLnkExt); base::FilePath shortcut_path(fake_user_desktop_.path().Append(shortcut_name)); ASSERT_TRUE(base::PathExists(shortcut_path)); base::FilePath new_exe = temp_dir_.path().Append(kManganeseExe); ShellUtil::ShortcutProperties updated_properties(ShellUtil::CURRENT_USER); updated_properties.set_target(new_exe); // |updated_properties| has arguments. ASSERT_TRUE(ShellUtil::UpdateShortcutsWithArgs( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER, chrome_exe_, updated_properties)); ShellUtil::ShortcutProperties expected_properties(test_properties_); expected_properties.set_target(new_exe); ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, expected_properties); } TEST_F(ShellUtilShortcutTest, UpdateSystemLevelChromeShortcutsWithArgs) { test_properties_.level = ShellUtil::SYSTEM_LEVEL; ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); string16 shortcut_name( dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) + installer::kLnkExt); base::FilePath shortcut_path( fake_common_desktop_.path().Append(shortcut_name)); ASSERT_TRUE(base::PathExists(shortcut_path)); base::FilePath new_exe = temp_dir_.path().Append(kManganeseExe); ShellUtil::ShortcutProperties updated_properties(ShellUtil::CURRENT_USER); updated_properties.set_target(new_exe); // |updated_properties| has arguments. ASSERT_TRUE(ShellUtil::UpdateShortcutsWithArgs( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::SYSTEM_LEVEL, chrome_exe_, updated_properties)); ShellUtil::ShortcutProperties expected_properties(test_properties_); expected_properties.set_target(new_exe); ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, expected_properties); } TEST_F(ShellUtilShortcutTest, UpdateMultipleChromeShortcutsWithArgs) { const wchar_t kShortcutName1[] = L"Chrome 1"; const wchar_t kShortcutName2[] = L"Chrome 2"; // Setup shortcut 1, which has empty arguments. test_properties_.set_shortcut_name(kShortcutName1); test_properties_.set_arguments(L""); ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); string16 shortcut1_name(string16(kShortcutName1).append(installer::kLnkExt)); base::FilePath shortcut1_path( fake_user_desktop_.path().Append(shortcut1_name)); ShellUtil::ShortcutProperties expected_properties1(test_properties_); // Setup shortcut 2, which has non-empty arguments. string16 shortcut2_args = L"--profile-directory=\"Profile 2\""; test_properties_.set_shortcut_name(kShortcutName2); test_properties_.set_arguments(shortcut2_args); ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); string16 shortcut2_name(string16(kShortcutName2).append(installer::kLnkExt)); base::FilePath shortcut2_path( fake_user_desktop_.path().Append(shortcut2_name)); ASSERT_TRUE(base::PathExists(shortcut2_path)); ShellUtil::ShortcutProperties expected_properties2(test_properties_); // Update shortcuts: target "manganese.exe" instead of "chrome.exe". base::FilePath new_exe = temp_dir_.path().Append(kManganeseExe); ShellUtil::ShortcutProperties updated_properties(ShellUtil::CURRENT_USER); updated_properties.set_target(new_exe); // Only changing shrotcuts that have non-empty arguments, i.e., shortcut 2. ASSERT_TRUE(ShellUtil::UpdateShortcutsWithArgs( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER, chrome_exe_, updated_properties)); // Verify shortcut 1. // |expected_properties1| was unchanged and still targets "chrome.exe", since // it has empty target, yet we passed |require_args| = true. ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, expected_properties1); // Verify shortcut 2. expected_properties2.set_target(new_exe); ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, expected_properties2); } TEST_F(ShellUtilShortcutTest, CreateMultipleStartMenuShortcutsAndRemoveFolder) { ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); test_properties_.set_shortcut_name(L"A second shortcut"); ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); base::FilePath chrome_shortcut_folder( fake_start_menu_.path().Append( dist_->GetStartMenuShortcutSubfolder( BrowserDistribution::SUBFOLDER_CHROME))); base::FilePath chrome_apps_shortcut_folder( fake_start_menu_.path().Append( dist_->GetStartMenuShortcutSubfolder( BrowserDistribution::SUBFOLDER_APPS))); base::FileEnumerator chrome_file_counter(chrome_shortcut_folder, false, base::FileEnumerator::FILES); int count = 0; while (!chrome_file_counter.Next().empty()) ++count; EXPECT_EQ(2, count); base::FileEnumerator chrome_apps_file_counter(chrome_apps_shortcut_folder, false, base::FileEnumerator::FILES); count = 0; while (!chrome_apps_file_counter.Next().empty()) ++count; EXPECT_EQ(2, count); ASSERT_TRUE(base::PathExists(chrome_shortcut_folder)); ASSERT_TRUE(ShellUtil::RemoveShortcuts( ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_, ShellUtil::CURRENT_USER, chrome_exe_)); ASSERT_FALSE(base::PathExists(chrome_shortcut_folder)); ASSERT_TRUE(base::PathExists(chrome_apps_shortcut_folder)); ASSERT_TRUE(ShellUtil::RemoveShortcuts( ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR, dist_, ShellUtil::CURRENT_USER, chrome_exe_)); ASSERT_FALSE(base::PathExists(chrome_apps_shortcut_folder)); } TEST_F(ShellUtilShortcutTest, DeleteStartMenuRootShortcutWithoutRemovingFolder) { ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); string16 shortcut_name( dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) + installer::kLnkExt); base::FilePath shortcut_path( fake_start_menu_.path().Append(shortcut_name)); ASSERT_TRUE(base::PathExists(fake_start_menu_.path())); ASSERT_TRUE(base::PathExists(shortcut_path)); ASSERT_TRUE(ShellUtil::RemoveShortcuts( ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT, dist_, ShellUtil::CURRENT_USER, chrome_exe_)); // The shortcut should be removed but the "Start Menu" root directory should // remain. ASSERT_TRUE(base::PathExists(fake_start_menu_.path())); ASSERT_FALSE(base::PathExists(shortcut_path)); } TEST_F(ShellUtilShortcutTest, DontRemoveChromeShortcutIfPointsToAnotherChrome) { base::ScopedTempDir other_exe_dir; ASSERT_TRUE(other_exe_dir.CreateUniqueTempDir()); base::FilePath other_chrome_exe = other_exe_dir.path().Append(installer::kChromeExe); EXPECT_EQ(0, file_util::WriteFile(other_chrome_exe, "", 0)); test_properties_.set_target(other_chrome_exe); ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)); string16 shortcut_name( dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) + installer::kLnkExt); base::FilePath shortcut_path(fake_user_desktop_.path().Append(shortcut_name)); ASSERT_TRUE(base::PathExists(shortcut_path)); // The shortcut shouldn't be removed as it was installed pointing to // |other_chrome_exe| and RemoveChromeShortcut() is being told that the // removed shortcut should point to |chrome_exe_|. ASSERT_TRUE(ShellUtil::RemoveShortcuts( ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER, chrome_exe_)); ASSERT_TRUE(base::PathExists(shortcut_path)); ASSERT_TRUE(base::PathExists(shortcut_path.DirName())); } TEST(ShellUtilTest, BuildAppModelIdBasic) { std::vector<string16> components; BrowserDistribution* dist = BrowserDistribution::GetDistribution(); const string16 base_app_id(dist->GetBaseAppId()); components.push_back(base_app_id); ASSERT_EQ(base_app_id, ShellUtil::BuildAppModelId(components)); } TEST(ShellUtilTest, BuildAppModelIdManySmall) { std::vector<string16> components; BrowserDistribution* dist = BrowserDistribution::GetDistribution(); const string16 suffixed_app_id(dist->GetBaseAppId().append(L".gab")); components.push_back(suffixed_app_id); components.push_back(L"Default"); components.push_back(L"Test"); ASSERT_EQ(suffixed_app_id + L".Default.Test", ShellUtil::BuildAppModelId(components)); } TEST(ShellUtilTest, BuildAppModelIdLongUsernameNormalProfile) { std::vector<string16> components; const string16 long_appname( L"Chrome.a_user_who_has_a_crazy_long_name_with_some_weird@symbols_in_it_" L"that_goes_over_64_characters"); components.push_back(long_appname); components.push_back(L"Default"); ASSERT_EQ(L"Chrome.a_user_wer_64_characters.Default", ShellUtil::BuildAppModelId(components)); } TEST(ShellUtilTest, BuildAppModelIdLongEverything) { std::vector<string16> components; const string16 long_appname( L"Chrome.a_user_who_has_a_crazy_long_name_with_some_weird@symbols_in_it_" L"that_goes_over_64_characters"); components.push_back(long_appname); components.push_back( L"A_crazy_profile_name_not_even_sure_whether_that_is_possible"); const string16 constructed_app_id(ShellUtil::BuildAppModelId(components)); ASSERT_LE(constructed_app_id.length(), installer::kMaxAppModelIdLength); ASSERT_EQ(L"Chrome.a_user_wer_64_characters.A_crazy_profilethat_is_possible", constructed_app_id); } TEST(ShellUtilTest, GetUserSpecificRegistrySuffix) { string16 suffix; ASSERT_TRUE(ShellUtil::GetUserSpecificRegistrySuffix(&suffix)); ASSERT_TRUE(StartsWith(suffix, L".", true)); ASSERT_EQ(27, suffix.length()); ASSERT_TRUE(ContainsOnlyChars(suffix.substr(1), L"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567")); } TEST(ShellUtilTest, GetOldUserSpecificRegistrySuffix) { string16 suffix; ASSERT_TRUE(ShellUtil::GetOldUserSpecificRegistrySuffix(&suffix)); ASSERT_TRUE(StartsWith(suffix, L".", true)); wchar_t user_name[256]; DWORD size = arraysize(user_name); ASSERT_NE(0, ::GetUserName(user_name, &size)); ASSERT_GE(size, 1U); ASSERT_STREQ(user_name, suffix.substr(1).c_str()); } TEST(ShellUtilTest, ByteArrayToBase32) { // Tests from http://tools.ietf.org/html/rfc4648#section-10. const unsigned char test_array[] = { 'f', 'o', 'o', 'b', 'a', 'r' }; const string16 expected[] = { L"", L"MY", L"MZXQ", L"MZXW6", L"MZXW6YQ", L"MZXW6YTB", L"MZXW6YTBOI"}; // Run the tests, with one more letter in the input every pass. for (int i = 0; i < arraysize(expected); ++i) { ASSERT_EQ(expected[i], ShellUtil::ByteArrayToBase32(test_array, i)); } }