| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 <string> | |
| 6 | |
| 7 #include "base/file_path.h" | |
| 8 #include "base/path_service.h" | |
| 9 #include "base/scoped_temp_dir.h" | |
| 10 #include "base/string_util.h" | |
| 11 #include "base/utf_string_conversions.h" | |
| 12 #include "chrome/browser/download/save_package.h" | |
| 13 #include "chrome/browser/ui/tab_contents/test_tab_contents_wrapper.h" | |
| 14 #include "content/browser/browser_thread.h" | |
| 15 #include "content/browser/net/url_request_mock_http_job.h" | |
| 16 #include "content/browser/tab_contents/test_tab_contents.h" | |
| 17 #include "googleurl/src/gurl.h" | |
| 18 #include "testing/gtest/include/gtest/gtest.h" | |
| 19 | |
| 20 #define FPL FILE_PATH_LITERAL | |
| 21 #if defined(OS_WIN) | |
| 22 #define HTML_EXTENSION ".htm" | |
| 23 // This second define is needed because MSVC is broken. | |
| 24 #define FPL_HTML_EXTENSION L".htm" | |
| 25 #else | |
| 26 #define HTML_EXTENSION ".html" | |
| 27 #define FPL_HTML_EXTENSION ".html" | |
| 28 #endif | |
| 29 | |
| 30 namespace { | |
| 31 | |
| 32 // This constant copied from save_package.cc. | |
| 33 #if defined(OS_WIN) | |
| 34 const uint32 kMaxFilePathLength = MAX_PATH - 1; | |
| 35 const uint32 kMaxFileNameLength = MAX_PATH - 1; | |
| 36 #elif defined(OS_POSIX) | |
| 37 const uint32 kMaxFilePathLength = PATH_MAX - 1; | |
| 38 const uint32 kMaxFileNameLength = NAME_MAX; | |
| 39 #endif | |
| 40 | |
| 41 // Used to make long filenames. | |
| 42 std::string long_file_name( | |
| 43 "EFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz01234567" | |
| 44 "89ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz012345" | |
| 45 "6789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz0123" | |
| 46 "456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789a"); | |
| 47 | |
| 48 bool HasOrdinalNumber(const FilePath::StringType& filename) { | |
| 49 FilePath::StringType::size_type r_paren_index = filename.rfind(FPL(')')); | |
| 50 FilePath::StringType::size_type l_paren_index = filename.rfind(FPL('(')); | |
| 51 if (l_paren_index >= r_paren_index) | |
| 52 return false; | |
| 53 | |
| 54 for (FilePath::StringType::size_type i = l_paren_index + 1; | |
| 55 i != r_paren_index; ++i) { | |
| 56 if (!IsAsciiDigit(filename[i])) | |
| 57 return false; | |
| 58 } | |
| 59 | |
| 60 return true; | |
| 61 } | |
| 62 | |
| 63 } // namespace | |
| 64 | |
| 65 class SavePackageTest : public TabContentsWrapperTestHarness { | |
| 66 public: | |
| 67 SavePackageTest() : browser_thread_(BrowserThread::UI, &message_loop_) { | |
| 68 } | |
| 69 | |
| 70 bool GetGeneratedFilename(bool need_success_generate_filename, | |
| 71 const std::string& disposition, | |
| 72 const std::string& url, | |
| 73 bool need_htm_ext, | |
| 74 FilePath::StringType* generated_name) { | |
| 75 SavePackage* save_package; | |
| 76 if (need_success_generate_filename) | |
| 77 save_package = save_package_success_.get(); | |
| 78 else | |
| 79 save_package = save_package_fail_.get(); | |
| 80 return save_package->GenerateFileName(disposition, GURL(url), need_htm_ext, | |
| 81 generated_name); | |
| 82 } | |
| 83 | |
| 84 FilePath EnsureHtmlExtension(const FilePath& name) { | |
| 85 return SavePackage::EnsureHtmlExtension(name); | |
| 86 } | |
| 87 | |
| 88 FilePath EnsureMimeExtension(const FilePath& name, | |
| 89 const std::string& content_mime_type) { | |
| 90 return SavePackage::EnsureMimeExtension(name, content_mime_type); | |
| 91 } | |
| 92 | |
| 93 GURL GetUrlToBeSaved() { | |
| 94 return save_package_success_->GetUrlToBeSaved(); | |
| 95 } | |
| 96 | |
| 97 protected: | |
| 98 virtual void SetUp() { | |
| 99 TabContentsWrapperTestHarness::SetUp(); | |
| 100 | |
| 101 // Do the initialization in SetUp so contents() is initialized by | |
| 102 // TabContentsWrapperTestHarness::SetUp. | |
| 103 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
| 104 | |
| 105 save_package_success_ = new SavePackage(contents_wrapper(), | |
| 106 temp_dir_.path().AppendASCII("testfile" HTML_EXTENSION), | |
| 107 temp_dir_.path().AppendASCII("testfile_files")); | |
| 108 | |
| 109 // We need to construct a path that is *almost* kMaxFilePathLength long | |
| 110 long_file_name.resize(kMaxFilePathLength + long_file_name.length()); | |
| 111 while (long_file_name.length() < kMaxFilePathLength) | |
| 112 long_file_name += long_file_name; | |
| 113 long_file_name.resize( | |
| 114 kMaxFilePathLength - 9 - temp_dir_.path().value().length()); | |
| 115 | |
| 116 save_package_fail_ = new SavePackage(contents_wrapper(), | |
| 117 temp_dir_.path().AppendASCII(long_file_name + HTML_EXTENSION), | |
| 118 temp_dir_.path().AppendASCII(long_file_name + "_files")); | |
| 119 } | |
| 120 | |
| 121 private: | |
| 122 BrowserThread browser_thread_; | |
| 123 | |
| 124 // SavePackage for successfully generating file name. | |
| 125 scoped_refptr<SavePackage> save_package_success_; | |
| 126 // SavePackage for failed generating file name. | |
| 127 scoped_refptr<SavePackage> save_package_fail_; | |
| 128 | |
| 129 ScopedTempDir temp_dir_; | |
| 130 | |
| 131 DISALLOW_COPY_AND_ASSIGN(SavePackageTest); | |
| 132 }; | |
| 133 | |
| 134 static const struct { | |
| 135 const char* disposition; | |
| 136 const char* url; | |
| 137 const FilePath::CharType* expected_name; | |
| 138 bool need_htm_ext; | |
| 139 } kGeneratedFiles[] = { | |
| 140 // We mainly focus on testing duplicated names here, since retrieving file | |
| 141 // name from disposition and url has been tested in DownloadManagerTest. | |
| 142 | |
| 143 // No useful information in disposition or URL, use default. | |
| 144 {"1.html", "http://www.savepage.com/", | |
| 145 FPL("saved_resource") FPL_HTML_EXTENSION, true}, | |
| 146 | |
| 147 // No duplicate occurs. | |
| 148 {"filename=1.css", "http://www.savepage.com", FPL("1.css"), false}, | |
| 149 | |
| 150 // No duplicate occurs. | |
| 151 {"filename=1.js", "http://www.savepage.com", FPL("1.js"), false}, | |
| 152 | |
| 153 // Append numbers for duplicated names. | |
| 154 {"filename=1.css", "http://www.savepage.com", FPL("1(1).css"), false}, | |
| 155 | |
| 156 // No duplicate occurs. | |
| 157 {"filename=1(1).js", "http://www.savepage.com", FPL("1(1).js"), false}, | |
| 158 | |
| 159 // Append numbers for duplicated names. | |
| 160 {"filename=1.css", "http://www.savepage.com", FPL("1(2).css"), false}, | |
| 161 | |
| 162 // Change number for duplicated names. | |
| 163 {"filename=1(1).css", "http://www.savepage.com", FPL("1(3).css"), false}, | |
| 164 | |
| 165 // No duplicate occurs. | |
| 166 {"filename=1(11).css", "http://www.savepage.com", FPL("1(11).css"), false}, | |
| 167 }; | |
| 168 | |
| 169 TEST_F(SavePackageTest, TestSuccessfullyGenerateSavePackageFilename) { | |
| 170 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kGeneratedFiles); ++i) { | |
| 171 FilePath::StringType file_name; | |
| 172 bool ok = GetGeneratedFilename(true, | |
| 173 kGeneratedFiles[i].disposition, | |
| 174 kGeneratedFiles[i].url, | |
| 175 kGeneratedFiles[i].need_htm_ext, | |
| 176 &file_name); | |
| 177 ASSERT_TRUE(ok); | |
| 178 EXPECT_EQ(kGeneratedFiles[i].expected_name, file_name); | |
| 179 } | |
| 180 } | |
| 181 | |
| 182 TEST_F(SavePackageTest, TestUnSuccessfullyGenerateSavePackageFilename) { | |
| 183 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kGeneratedFiles); ++i) { | |
| 184 FilePath::StringType file_name; | |
| 185 bool ok = GetGeneratedFilename(false, | |
| 186 kGeneratedFiles[i].disposition, | |
| 187 kGeneratedFiles[i].url, | |
| 188 kGeneratedFiles[i].need_htm_ext, | |
| 189 &file_name); | |
| 190 ASSERT_FALSE(ok); | |
| 191 } | |
| 192 } | |
| 193 | |
| 194 // Crashing on Windows, see http://crbug.com/79365 | |
| 195 #if defined(OS_WIN) | |
| 196 #define MAYBE_TestLongSavePackageFilename DISABLED_TestLongSavePackageFilename | |
| 197 #else | |
| 198 #define MAYBE_TestLongSavePackageFilename TestLongSavePackageFilename | |
| 199 #endif | |
| 200 TEST_F(SavePackageTest, MAYBE_TestLongSavePackageFilename) { | |
| 201 const std::string base_url("http://www.google.com/"); | |
| 202 const std::string long_file = long_file_name + ".css"; | |
| 203 const std::string url = base_url + long_file; | |
| 204 | |
| 205 FilePath::StringType filename; | |
| 206 // Test that the filename is successfully shortened to fit. | |
| 207 ASSERT_TRUE(GetGeneratedFilename(true, "", url, false, &filename)); | |
| 208 EXPECT_TRUE(filename.length() < long_file.length()); | |
| 209 EXPECT_FALSE(HasOrdinalNumber(filename)); | |
| 210 | |
| 211 // Test that the filename is successfully shortened to fit, and gets an | |
| 212 // an ordinal appended. | |
| 213 ASSERT_TRUE(GetGeneratedFilename(true, "", url, false, &filename)); | |
| 214 EXPECT_TRUE(filename.length() < long_file.length()); | |
| 215 EXPECT_TRUE(HasOrdinalNumber(filename)); | |
| 216 | |
| 217 // Test that the filename is successfully shortened to fit, and gets a | |
| 218 // different ordinal appended. | |
| 219 FilePath::StringType filename2; | |
| 220 ASSERT_TRUE(GetGeneratedFilename(true, "", url, false, &filename2)); | |
| 221 EXPECT_TRUE(filename2.length() < long_file.length()); | |
| 222 EXPECT_TRUE(HasOrdinalNumber(filename2)); | |
| 223 EXPECT_NE(filename, filename2); | |
| 224 } | |
| 225 | |
| 226 // Crashing on Windows, see http://crbug.com/79365 | |
| 227 #if defined(OS_WIN) | |
| 228 #define MAYBE_TestLongSafePureFilename DISABLED_TestLongSafePureFilename | |
| 229 #else | |
| 230 #define MAYBE_TestLongSafePureFilename TestLongSafePureFilename | |
| 231 #endif | |
| 232 TEST_F(SavePackageTest, MAYBE_TestLongSafePureFilename) { | |
| 233 const FilePath save_dir(FPL("test_dir")); | |
| 234 const FilePath::StringType ext(FPL_HTML_EXTENSION); | |
| 235 FilePath::StringType filename = | |
| 236 #if defined(OS_WIN) | |
| 237 ASCIIToWide(long_file_name); | |
| 238 #else | |
| 239 long_file_name; | |
| 240 #endif | |
| 241 | |
| 242 // Test that the filename + extension doesn't exceed kMaxFileNameLength | |
| 243 uint32 max_path = SavePackage::GetMaxPathLengthForDirectory(save_dir); | |
| 244 ASSERT_TRUE(SavePackage::GetSafePureFileName(save_dir, ext, max_path, | |
| 245 &filename)); | |
| 246 EXPECT_TRUE(filename.length() <= kMaxFileNameLength-ext.length()); | |
| 247 } | |
| 248 | |
| 249 static const struct { | |
| 250 const FilePath::CharType* page_title; | |
| 251 const FilePath::CharType* expected_name; | |
| 252 } kExtensionTestCases[] = { | |
| 253 // Extension is preserved if it is already proper for HTML. | |
| 254 {FPL("filename.html"), FPL("filename.html")}, | |
| 255 {FPL("filename.HTML"), FPL("filename.HTML")}, | |
| 256 {FPL("filename.XHTML"), FPL("filename.XHTML")}, | |
| 257 {FPL("filename.xhtml"), FPL("filename.xhtml")}, | |
| 258 {FPL("filename.htm"), FPL("filename.htm")}, | |
| 259 // ".htm" is added if the extension is improper for HTML. | |
| 260 {FPL("hello.world"), FPL("hello.world") FPL_HTML_EXTENSION}, | |
| 261 {FPL("hello.txt"), FPL("hello.txt") FPL_HTML_EXTENSION}, | |
| 262 {FPL("is.html.good"), FPL("is.html.good") FPL_HTML_EXTENSION}, | |
| 263 // ".htm" is added if the name doesn't have an extension. | |
| 264 {FPL("helloworld"), FPL("helloworld") FPL_HTML_EXTENSION}, | |
| 265 {FPL("helloworld."), FPL("helloworld.") FPL_HTML_EXTENSION}, | |
| 266 }; | |
| 267 | |
| 268 // Crashing on Windows, see http://crbug.com/79365 | |
| 269 #if defined(OS_WIN) | |
| 270 #define MAYBE_TestEnsureHtmlExtension DISABLED_TestEnsureHtmlExtension | |
| 271 #else | |
| 272 #define MAYBE_TestEnsureHtmlExtension TestEnsureHtmlExtension | |
| 273 #endif | |
| 274 TEST_F(SavePackageTest, MAYBE_TestEnsureHtmlExtension) { | |
| 275 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExtensionTestCases); ++i) { | |
| 276 FilePath original = FilePath(kExtensionTestCases[i].page_title); | |
| 277 FilePath expected = FilePath(kExtensionTestCases[i].expected_name); | |
| 278 FilePath actual = EnsureHtmlExtension(original); | |
| 279 EXPECT_EQ(expected.value(), actual.value()) << "Failed for page title: " << | |
| 280 kExtensionTestCases[i].page_title; | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 // Crashing on Windows, see http://crbug.com/79365 | |
| 285 #if defined(OS_WIN) | |
| 286 #define MAYBE_TestEnsureMimeExtension DISABLED_TestEnsureMimeExtension | |
| 287 #else | |
| 288 #define MAYBE_TestEnsureMimeExtension TestEnsureMimeExtension | |
| 289 #endif | |
| 290 TEST_F(SavePackageTest, MAYBE_TestEnsureMimeExtension) { | |
| 291 static const struct { | |
| 292 const FilePath::CharType* page_title; | |
| 293 const FilePath::CharType* expected_name; | |
| 294 const char* contents_mime_type; | |
| 295 } kExtensionTests[] = { | |
| 296 { FPL("filename.html"), FPL("filename.html"), "text/html" }, | |
| 297 { FPL("filename.htm"), FPL("filename.htm"), "text/html" }, | |
| 298 { FPL("filename.xhtml"), FPL("filename.xhtml"), "text/html" }, | |
| 299 #if defined(OS_WIN) | |
| 300 { FPL("filename"), FPL("filename.htm"), "text/html" }, | |
| 301 #else // defined(OS_WIN) | |
| 302 { FPL("filename"), FPL("filename.html"), "text/html" }, | |
| 303 #endif // defined(OS_WIN) | |
| 304 { FPL("filename.html"), FPL("filename.html"), "text/xml" }, | |
| 305 { FPL("filename.xml"), FPL("filename.xml"), "text/xml" }, | |
| 306 { FPL("filename"), FPL("filename.xml"), "text/xml" }, | |
| 307 { FPL("filename.xhtml"), FPL("filename.xhtml"), | |
| 308 "application/xhtml+xml" }, | |
| 309 { FPL("filename.html"), FPL("filename.html"), | |
| 310 "application/xhtml+xml" }, | |
| 311 { FPL("filename"), FPL("filename.xhtml"), "application/xhtml+xml" }, | |
| 312 { FPL("filename.txt"), FPL("filename.txt"), "text/plain" }, | |
| 313 { FPL("filename"), FPL("filename.txt"), "text/plain" }, | |
| 314 { FPL("filename.css"), FPL("filename.css"), "text/css" }, | |
| 315 { FPL("filename"), FPL("filename.css"), "text/css" }, | |
| 316 { FPL("filename.abc"), FPL("filename.abc"), "unknown/unknown" }, | |
| 317 { FPL("filename"), FPL("filename"), "unknown/unknown" }, | |
| 318 }; | |
| 319 for (uint32 i = 0; i < ARRAYSIZE_UNSAFE(kExtensionTests); ++i) { | |
| 320 FilePath original = FilePath(kExtensionTests[i].page_title); | |
| 321 FilePath expected = FilePath(kExtensionTests[i].expected_name); | |
| 322 std::string mime_type(kExtensionTests[i].contents_mime_type); | |
| 323 FilePath actual = EnsureMimeExtension(original, mime_type); | |
| 324 EXPECT_EQ(expected.value(), actual.value()) << "Failed for page title: " << | |
| 325 kExtensionTests[i].page_title << " MIME:" << mime_type; | |
| 326 } | |
| 327 } | |
| 328 | |
| 329 // Test that the suggested names generated by SavePackage are reasonable: | |
| 330 // If the name is a URL, retrieve only the path component since the path name | |
| 331 // generation code will turn the entire URL into the file name leading to bad | |
| 332 // extension names. For example, a page with no title and a URL: | |
| 333 // http://www.foo.com/a/path/name.txt will turn into file: | |
| 334 // "http www.foo.com a path name.txt", when we want to save it as "name.txt". | |
| 335 | |
| 336 static const struct SuggestedSaveNameTestCase { | |
| 337 const char* page_url; | |
| 338 const string16 page_title; | |
| 339 const FilePath::CharType* expected_name; | |
| 340 bool ensure_html_extension; | |
| 341 } kSuggestedSaveNames[] = { | |
| 342 // Title overrides the URL. | |
| 343 { "http://foo.com", | |
| 344 ASCIIToUTF16("A page title"), | |
| 345 FPL("A page title") FPL_HTML_EXTENSION, | |
| 346 true | |
| 347 }, | |
| 348 // Extension is preserved. | |
| 349 { "http://foo.com", | |
| 350 ASCIIToUTF16("A page title with.ext"), | |
| 351 FPL("A page title with.ext"), | |
| 352 false | |
| 353 }, | |
| 354 // If the title matches the URL, use the last component of the URL. | |
| 355 { "http://foo.com/bar", | |
| 356 ASCIIToUTF16("http://foo.com/bar"), | |
| 357 FPL("bar"), | |
| 358 false | |
| 359 }, | |
| 360 // If the title matches the URL, but there is no "filename" component, | |
| 361 // use the domain. | |
| 362 { "http://foo.com", | |
| 363 ASCIIToUTF16("http://foo.com"), | |
| 364 FPL("foo.com"), | |
| 365 false | |
| 366 }, | |
| 367 // Make sure fuzzy matching works. | |
| 368 { "http://foo.com/bar", | |
| 369 ASCIIToUTF16("foo.com/bar"), | |
| 370 FPL("bar"), | |
| 371 false | |
| 372 }, | |
| 373 // A URL-like title that does not match the title is respected in full. | |
| 374 { "http://foo.com", | |
| 375 ASCIIToUTF16("http://www.foo.com/path/title.txt"), | |
| 376 FPL("http www.foo.com path title.txt"), | |
| 377 false | |
| 378 }, | |
| 379 }; | |
| 380 | |
| 381 // Crashing on Windows, see http://crbug.com/79365 | |
| 382 #if defined(OS_WIN) | |
| 383 #define MAYBE_TestSuggestedSaveNames DISABLED_TestSuggestedSaveNames | |
| 384 #else | |
| 385 #define MAYBE_TestSuggestedSaveNames TestSuggestedSaveNames | |
| 386 #endif | |
| 387 TEST_F(SavePackageTest, MAYBE_TestSuggestedSaveNames) { | |
| 388 for (size_t i = 0; i < arraysize(kSuggestedSaveNames); ++i) { | |
| 389 scoped_refptr<SavePackage> save_package( | |
| 390 new SavePackage(contents_wrapper(), FilePath(), FilePath())); | |
| 391 save_package->page_url_ = GURL(kSuggestedSaveNames[i].page_url); | |
| 392 save_package->title_ = kSuggestedSaveNames[i].page_title; | |
| 393 | |
| 394 FilePath save_name = save_package->GetSuggestedNameForSaveAs( | |
| 395 kSuggestedSaveNames[i].ensure_html_extension, | |
| 396 std::string()); | |
| 397 EXPECT_EQ(kSuggestedSaveNames[i].expected_name, save_name.value()) << | |
| 398 "Test case " << i; | |
| 399 } | |
| 400 } | |
| 401 | |
| 402 static const FilePath::CharType* kTestDir = FILE_PATH_LITERAL("save_page"); | |
| 403 | |
| 404 // GetUrlToBeSaved method should return correct url to be saved. | |
| 405 TEST_F(SavePackageTest, TestGetUrlToBeSaved) { | |
| 406 FilePath file_name(FILE_PATH_LITERAL("a.htm")); | |
| 407 GURL url = URLRequestMockHTTPJob::GetMockUrl( | |
| 408 FilePath(kTestDir).Append(file_name)); | |
| 409 NavigateAndCommit(url); | |
| 410 EXPECT_EQ(url, GetUrlToBeSaved()); | |
| 411 } | |
| 412 | |
| 413 // GetUrlToBeSaved method sould return actual url to be saved, | |
| 414 // instead of the displayed url used to view source of a page. | |
| 415 // Ex:GetUrlToBeSaved method should return http://www.google.com | |
| 416 // when user types view-source:http://www.google.com | |
| 417 TEST_F(SavePackageTest, TestGetUrlToBeSavedViewSource) { | |
| 418 FilePath file_name(FILE_PATH_LITERAL("a.htm")); | |
| 419 GURL view_source_url = URLRequestMockHTTPJob::GetMockViewSourceUrl( | |
| 420 FilePath(kTestDir).Append(file_name)); | |
| 421 GURL actual_url = URLRequestMockHTTPJob::GetMockUrl( | |
| 422 FilePath(kTestDir).Append(file_name)); | |
| 423 NavigateAndCommit(view_source_url); | |
| 424 EXPECT_EQ(actual_url, GetUrlToBeSaved()); | |
| 425 EXPECT_EQ(view_source_url, contents()->GetURL()); | |
| 426 } | |
| OLD | NEW |