Logo Search packages:      
Sourcecode: chromium-browser version File versions  Download package

save_package_unittest.cc

// Copyright (c) 2006-2008 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 <string>

#include "base/file_path.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "chrome/browser/download/save_package.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"

#define FPL FILE_PATH_LITERAL
#if defined(OS_WIN)
#define HTML_EXTENSION ".htm"
// This second define is needed because MSVC is broken.
#define FPL_HTML_EXTENSION L".htm"
#else
#define HTML_EXTENSION ".html"
#define FPL_HTML_EXTENSION ".html"
#endif

namespace {

// This constant copied from save_package.cc.
#if defined(OS_WIN)
const uint32 kMaxFilePathLength = MAX_PATH - 1;
#elif defined(OS_POSIX)
const uint32 kMaxFilePathLength = PATH_MAX - 1;
#endif

// Used to make long filenames.
std::string long_file_name(
    "EFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz01234567"
    "89ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz012345"
    "6789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz0123"
    "456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789a");

bool HasOrdinalNumber(const FilePath::StringType& filename) {
  FilePath::StringType::size_type r_paren_index = filename.rfind(FPL(')'));
  FilePath::StringType::size_type l_paren_index = filename.rfind(FPL('('));
  if (l_paren_index >= r_paren_index)
    return false;

  for (FilePath::StringType::size_type i = l_paren_index + 1;
       i != r_paren_index; ++i) {
    if (!IsAsciiDigit(filename[i]))
      return false;
  }

  return true;
}

}  // namespace

class SavePackageTest : public RenderViewHostTestHarness {
 public:
  SavePackageTest() {
  }

  bool GetGeneratedFilename(bool need_success_generate_filename,
                            const std::string& disposition,
                            const std::string& url,
                            bool need_htm_ext,
                            FilePath::StringType* generated_name) {
    SavePackage* save_package;
    if (need_success_generate_filename)
      save_package = save_package_success_.get();
    else
      save_package = save_package_fail_.get();
    return save_package->GenerateFileName(disposition, GURL(url), need_htm_ext,
                                          generated_name);
  }

  FilePath EnsureHtmlExtension(const FilePath& name) {
    return SavePackage::EnsureHtmlExtension(name);
  }

  FilePath EnsureMimeExtension(const FilePath& name,
                               const FilePath::StringType& content_mime_type) {
    return SavePackage::EnsureMimeExtension(name, content_mime_type);
  }

  FilePath GetSuggestedNameForSaveAs(const FilePath& title,
      bool ensure_html_extension,
      const FilePath::StringType& contents_mime_type) {
    return SavePackage::GetSuggestedNameForSaveAs(title, ensure_html_extension,
                                                  contents_mime_type);
  }

  GURL GetUrlToBeSaved() {
    return save_package_success_->GetUrlToBeSaved();
  }

 protected:
  virtual void SetUp() {
    RenderViewHostTestHarness::SetUp();

    // Do the initialization in SetUp so contents() is initialized by
    // RenderViewHostTestHarness::SetUp.
    FilePath test_dir;
    PathService::Get(base::DIR_TEMP, &test_dir);

    save_package_success_ = new SavePackage(contents(),
        test_dir.AppendASCII("testfile" HTML_EXTENSION),
        test_dir.AppendASCII("testfile_files"));

    // We need to construct a path that is *almost* kMaxFilePathLength long
    long_file_name.resize(kMaxFilePathLength + long_file_name.length());
    while (long_file_name.length() < kMaxFilePathLength)
      long_file_name += long_file_name;
    long_file_name.resize(kMaxFilePathLength - 9 - test_dir.value().length());

    save_package_fail_ = new SavePackage(contents(),
        test_dir.AppendASCII(long_file_name + HTML_EXTENSION),
        test_dir.AppendASCII(long_file_name + "_files"));
  }

 private:
  // SavePackage for successfully generating file name.
  scoped_refptr<SavePackage> save_package_success_;
  // SavePackage for failed generating file name.
  scoped_refptr<SavePackage> save_package_fail_;

  DISALLOW_COPY_AND_ASSIGN(SavePackageTest);
};

static const struct {
  const char* disposition;
  const char* url;
  const FilePath::CharType* expected_name;
  bool need_htm_ext;
} kGeneratedFiles[] = {
  // We mainly focus on testing duplicated names here, since retrieving file
  // name from disposition and url has been tested in DownloadManagerTest.

  // No useful information in disposition or URL, use default.
  {"1.html", "http://www.savepage.com/",
    FPL("saved_resource") FPL_HTML_EXTENSION, true},

  // No duplicate occurs.
  {"filename=1.css", "http://www.savepage.com", FPL("1.css"), false},

  // No duplicate occurs.
  {"filename=1.js", "http://www.savepage.com", FPL("1.js"), false},

  // Append numbers for duplicated names.
  {"filename=1.css", "http://www.savepage.com", FPL("1(1).css"), false},

  // No duplicate occurs.
  {"filename=1(1).js", "http://www.savepage.com", FPL("1(1).js"), false},

  // Append numbers for duplicated names.
  {"filename=1.css", "http://www.savepage.com", FPL("1(2).css"), false},

  // Change number for duplicated names.
  {"filename=1(1).css", "http://www.savepage.com", FPL("1(3).css"), false},

  // No duplicate occurs.
  {"filename=1(11).css", "http://www.savepage.com", FPL("1(11).css"), false},
};

TEST_F(SavePackageTest, TestSuccessfullyGenerateSavePackageFilename) {
  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kGeneratedFiles); ++i) {
    FilePath::StringType file_name;
    bool ok = GetGeneratedFilename(true,
                                   kGeneratedFiles[i].disposition,
                                   kGeneratedFiles[i].url,
                                   kGeneratedFiles[i].need_htm_ext,
                                   &file_name);
    ASSERT_TRUE(ok);
    EXPECT_EQ(kGeneratedFiles[i].expected_name, file_name);
  }
}

TEST_F(SavePackageTest, TestUnSuccessfullyGenerateSavePackageFilename) {
  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kGeneratedFiles); ++i) {
    FilePath::StringType file_name;
    bool ok = GetGeneratedFilename(false,
                                   kGeneratedFiles[i].disposition,
                                   kGeneratedFiles[i].url,
                                   kGeneratedFiles[i].need_htm_ext,
                                   &file_name);
    ASSERT_FALSE(ok);
  }
}

TEST_F(SavePackageTest, TestLongSavePackageFilename) {
  const std::string base_url("http://www.google.com/");
  const std::string long_file = long_file_name + ".css";
  const std::string url = base_url + long_file;

  FilePath::StringType filename;
  // Test that the filename is successfully shortened to fit.
  ASSERT_TRUE(GetGeneratedFilename(true, "", url, false, &filename));
  EXPECT_TRUE(filename.length() < long_file.length());
  EXPECT_FALSE(HasOrdinalNumber(filename));

  // Test that the filename is successfully shortened to fit, and gets an
  // an ordinal appended.
  ASSERT_TRUE(GetGeneratedFilename(true, "", url, false, &filename));
  EXPECT_TRUE(filename.length() < long_file.length());
  EXPECT_TRUE(HasOrdinalNumber(filename));

  // Test that the filename is successfully shortened to fit, and gets a
  // different ordinal appended.
  FilePath::StringType filename2;
  ASSERT_TRUE(GetGeneratedFilename(true, "", url, false, &filename2));
  EXPECT_TRUE(filename2.length() < long_file.length());
  EXPECT_TRUE(HasOrdinalNumber(filename2));
  EXPECT_NE(filename, filename2);
}

static const struct {
  const FilePath::CharType* page_title;
  const FilePath::CharType* expected_name;
} kExtensionTestCases[] = {
  // Extension is preserved if it is already proper for HTML.
  {FPL("filename.html"), FPL("filename.html")},
  {FPL("filename.HTML"), FPL("filename.HTML")},
  {FPL("filename.XHTML"), FPL("filename.XHTML")},
  {FPL("filename.xhtml"), FPL("filename.xhtml")},
  {FPL("filename.htm"), FPL("filename.htm")},
  // ".htm" is added if the extension is improper for HTML.
  {FPL("hello.world"), FPL("hello.world") FPL_HTML_EXTENSION},
  {FPL("hello.txt"), FPL("hello.txt") FPL_HTML_EXTENSION},
  {FPL("is.html.good"), FPL("is.html.good") FPL_HTML_EXTENSION},
  // ".htm" is added if the name doesn't have an extension.
  {FPL("helloworld"), FPL("helloworld") FPL_HTML_EXTENSION},
  {FPL("helloworld."), FPL("helloworld.") FPL_HTML_EXTENSION},
};

TEST_F(SavePackageTest, TestEnsureHtmlExtension) {
  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExtensionTestCases); ++i) {
    FilePath original = FilePath(kExtensionTestCases[i].page_title);
    FilePath expected = FilePath(kExtensionTestCases[i].expected_name);
    FilePath actual = EnsureHtmlExtension(original);
    EXPECT_EQ(expected.value(), actual.value()) << "Failed for page title: " <<
        kExtensionTestCases[i].page_title;
  }
}

TEST_F(SavePackageTest, TestEnsureMimeExtension) {
  static const struct {
    const FilePath::CharType* page_title;
    const FilePath::CharType* expected_name;
    const FilePath::CharType* contents_mime_type;
  } kExtensionTests[] = {
    { FPL("filename.html"), FPL("filename.html"), FPL("text/html") },
    { FPL("filename.htm"), FPL("filename.htm"), FPL("text/html") },
    { FPL("filename.xhtml"), FPL("filename.xhtml"), FPL("text/html") },
#if defined(OS_WIN)
    { FPL("filename"), FPL("filename.htm"), FPL("text/html") },
#else  // defined(OS_WIN)
    { FPL("filename"), FPL("filename.html"), FPL("text/html") },
#endif  // defined(OS_WIN)
    { FPL("filename.html"), FPL("filename.html"), FPL("text/xml") },
    { FPL("filename.xml"), FPL("filename.xml"), FPL("text/xml") },
    { FPL("filename"), FPL("filename.xml"), FPL("text/xml") },
    { FPL("filename.xhtml"), FPL("filename.xhtml"),
      FPL("application/xhtml+xml") },
    { FPL("filename.html"), FPL("filename.html"),
      FPL("application/xhtml+xml") },
    { FPL("filename"), FPL("filename.xhtml"), FPL("application/xhtml+xml") },
    { FPL("filename.txt"), FPL("filename.txt"), FPL("text/plain") },
    { FPL("filename"), FPL("filename.txt"), FPL("text/plain") },
    { FPL("filename.css"), FPL("filename.css"), FPL("text/css") },
    { FPL("filename"), FPL("filename.css"), FPL("text/css") },
    { FPL("filename.abc"), FPL("filename.abc"), FPL("unknown/unknown") },
    { FPL("filename"), FPL("filename"), FPL("unknown/unknown") },
  };
  for (uint32 i = 0; i < ARRAYSIZE_UNSAFE(kExtensionTests); ++i) {
    FilePath original = FilePath(kExtensionTests[i].page_title);
    FilePath expected = FilePath(kExtensionTests[i].expected_name);
    FilePath::StringType mime_type(kExtensionTests[i].contents_mime_type);
    FilePath actual = EnsureMimeExtension(original, mime_type);
    EXPECT_EQ(expected.value(), actual.value()) << "Failed for page title: " <<
        kExtensionTests[i].page_title << " MIME:" << mime_type;
  }
}

// Test that the suggested names generated by SavePackage are reasonable:
// If the name is a URL, retrieve only the path component since the path name
// generation code will turn the entire URL into the file name leading to bad
// extension names. For example, a page with no title and a URL:
// http://www.foo.com/a/path/name.txt will turn into file:
// "http www.foo.com a path name.txt", when we want to save it as "name.txt".

static const struct {
  const FilePath::CharType* page_title;
  const FilePath::CharType* expected_name;
  bool ensure_html_extension;
} kSuggestedSaveNames[] = {
  {FPL("A page title"), FPL("A page title") FPL_HTML_EXTENSION, true},
  {FPL("A page title with.ext"), FPL("A page title with.ext"), false},
  {FPL("http://www.foo.com/path/title.txt"), FPL("title.txt"), false},
  {FPL("http://www.foo.com/path/"), FPL("path"), false},
  {FPL("http://www.foo.com/"), FPL("www.foo.com"), false},
};

TEST_F(SavePackageTest, TestSuggestedSaveNames) {
  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSuggestedSaveNames); ++i) {
    FilePath title = FilePath(kSuggestedSaveNames[i].page_title);
    FilePath save_name =
        GetSuggestedNameForSaveAs(title,
                                  kSuggestedSaveNames[i].ensure_html_extension,
                                  FilePath::StringType());
    EXPECT_EQ(save_name.value(), kSuggestedSaveNames[i].expected_name);
  }
}

static const FilePath::CharType* kTestDir = FILE_PATH_LITERAL("save_page");

// GetUrlToBeSaved method should return correct url to be saved.
TEST_F(SavePackageTest, TestGetUrlToBeSaved) {
  FilePath file_name(FILE_PATH_LITERAL("a.htm"));
  GURL url = URLRequestMockHTTPJob::GetMockUrl(
                 FilePath(kTestDir).Append(file_name));
  NavigateAndCommit(url);
  EXPECT_EQ(url, GetUrlToBeSaved());
}

// GetUrlToBeSaved method sould return actual url to be saved,
// instead of the displayed url used to view source of a page.
// Ex:GetUrlToBeSaved method should return http://www.google.com
// when user types view-source:http://www.google.com
TEST_F(SavePackageTest, TestGetUrlToBeSavedViewSource) {
  FilePath file_name(FILE_PATH_LITERAL("a.htm"));
  GURL view_source_url = URLRequestMockHTTPJob::GetMockViewSourceUrl(
                             FilePath(kTestDir).Append(file_name));
  GURL actual_url = URLRequestMockHTTPJob::GetMockUrl(
                        FilePath(kTestDir).Append(file_name));
  NavigateAndCommit(view_source_url);
  EXPECT_EQ(actual_url, GetUrlToBeSaved());
  EXPECT_EQ(view_source_url, contents()->GetURL());
}


Generated by  Doxygen 1.6.0   Back to index