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