DesktopLauncherTest.cpp (5282B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 #include "gtest/gtest.h" 5 #include <windows.h> 6 #include <string> 7 #include <optional> 8 #include <shellapi.h> 9 10 #include "find_firefox.h" 11 #include "tempfile_name.h" 12 #include "download_firefox.h" 13 #include "data_sink.h" 14 #include "file_sink.h" 15 16 static std::optional<std::wstring> get_value_from_key( 17 const wchar_t* key_path, const wchar_t* value_path) { 18 // First we need to get the current version of Firefox 19 wchar_t buffer[MAX_PATH]{}; 20 DWORD buffer_size = sizeof buffer; 21 LSTATUS status = RegGetValueW(HKEY_CURRENT_USER, key_path, value_path, 22 RRF_RT_REG_SZ, nullptr, buffer, &buffer_size); 23 if (status != ERROR_SUCCESS) { 24 return std::nullopt; 25 } 26 return std::wstring(buffer); 27 } 28 29 static bool set_value_for_key(const wchar_t* key_path, 30 const wchar_t* value_path, 31 const std::wstring& value) { 32 LSTATUS status = RegSetKeyValueW(HKEY_CURRENT_USER, key_path, value_path, 33 REG_SZ, value.c_str(), value.size() * 2 + 2); 34 return status == ERROR_SUCCESS; 35 } 36 37 static bool clear_value_for_key(const wchar_t* key_path, 38 const wchar_t* value_path) { 39 LSTATUS status = RegDeleteKeyValueW(HKEY_CURRENT_USER, key_path, value_path); 40 return status == ERROR_SUCCESS; 41 } 42 43 static bool delete_key(const wchar_t* key_path) { 44 LSTATUS status = RegDeleteKeyW(HKEY_CURRENT_USER, key_path); 45 return status == ERROR_SUCCESS; 46 } 47 48 class DesktopLauncherTest : public ::testing::Test { 49 protected: 50 HANDLE serverProcessHandle = nullptr; 51 std::optional<std::wstring> savedFirefoxVersion = std::nullopt; 52 std::optional<std::wstring> savedFirefoxPath = std::nullopt; 53 std::wstring base_key = getFirefoxRegistryBranding(); 54 std::wstring test_version = L"test.0.0.0.0"; 55 std::wstring test_path = L"This is a test"; 56 std::wstring test_base = base_key + L"\\" + test_version; 57 std::wstring test_subkey = test_base + L"\\Main"; 58 59 void SetUp() override { 60 savedFirefoxVersion = 61 get_value_from_key(base_key.c_str(), L"CurrentVersion"); 62 if (savedFirefoxVersion.has_value()) { 63 std::wstring subkey = base_key + L"\\" + savedFirefoxVersion.value(); 64 savedFirefoxPath = get_value_from_key(subkey.c_str(), L"PathToExe"); 65 } 66 set_value_for_key(base_key.c_str(), L"CurrentVersion", test_version); 67 set_value_for_key(test_subkey.c_str(), L"PathToExe", test_path); 68 // Override values 69 } 70 71 void TearDown() override { 72 if (savedFirefoxVersion.has_value()) { 73 set_value_for_key(base_key.c_str(), L"CurrentVersion", 74 savedFirefoxVersion.value()); 75 } else { 76 clear_value_for_key(base_key.c_str(), L"CurrentVersion"); 77 } 78 delete_key(test_subkey.c_str()); 79 delete_key(test_base.c_str()); 80 } 81 }; 82 83 TEST_F(DesktopLauncherTest, FirefoxPathTest) { 84 std::optional<std::wstring> path = lookupFirefoxPath(); 85 ASSERT_TRUE(path.has_value()); 86 ASSERT_EQ(path.value(), test_path); 87 } 88 89 TEST_F(DesktopLauncherTest, TempFileNameTest) { 90 std::optional<std::wstring> path = get_tempfile_name(); 91 ASSERT_TRUE(path.has_value()); 92 ASSERT_TRUE(path.value().find(std::wstring(L".exe")) > 0); 93 ASSERT_TRUE(path.value().find(std::wstring(L":\\")) > 0); 94 } 95 96 TEST_F(DesktopLauncherTest, TestGetObjectName) { 97 std::optional<std::wstring> objectName = get_object_name(); 98 ASSERT_TRUE(objectName.has_value()); 99 // The object name is a path, not a URL. 100 ASSERT_EQ(std::wstring::npos, 101 objectName.value().find(L"https://download.mozilla.org/")); 102 ASSERT_NE(std::wstring::npos, objectName.value().find(L"lang=")); 103 ASSERT_NE(std::wstring::npos, objectName.value().find(L"product=")); 104 } 105 106 TEST_F(DesktopLauncherTest, TestTempFileNamesAreDifferent) { 107 std::wstring temp1 = get_tempfile_name().value(); 108 std::wstring temp2 = get_tempfile_name().value(); 109 ASSERT_NE(temp1, temp2); 110 } 111 112 TEST_F(DesktopLauncherTest, TestFileSinkFreeze) { 113 std::wstring path = get_tempfile_name().value(); 114 115 auto delete_expecting_error = [](const wchar_t* path, DWORD expected) { 116 SetLastError(ERROR_SUCCESS); 117 BOOL result = DeleteFileW(path); 118 DWORD lastError = GetLastError(); 119 ASSERT_EQ(result, expected == ERROR_SUCCESS); 120 ASSERT_EQ(lastError, expected); 121 }; 122 123 char data[] = "important data"; 124 125 { 126 FileSink sink; 127 delete_expecting_error(path.c_str(), ERROR_FILE_NOT_FOUND); 128 ASSERT_TRUE(sink.open(path)); 129 delete_expecting_error(path.c_str(), ERROR_SHARING_VIOLATION); 130 ASSERT_TRUE(sink.accept(data, sizeof(data) - 1)); 131 delete_expecting_error(path.c_str(), ERROR_SHARING_VIOLATION); 132 ASSERT_TRUE(sink.freeze()); 133 delete_expecting_error(path.c_str(), ERROR_SHARING_VIOLATION); 134 ASSERT_FALSE(sink.accept(data, sizeof(data) - 1)); 135 136 // TODO: Automatically test that the path can be run with ShellExecuteEx 137 // or similar. 138 // 139 // To test this manually, run the launcher without Firefox installed. You 140 // should see a prompt to install Firefox; if so, then it was executable. 141 } 142 delete_expecting_error(path.c_str(), ERROR_SUCCESS); 143 }