// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/utility/importer/safari_importer.h"

#include <stddef.h>
#include <stdint.h>

#include <string>

#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/importer/importer_bridge.h"
#include "chrome/common/importer/safari_importer_utils.h"
#include "chrome/utility/importer/safari_importer.h"
#include "components/favicon_base/favicon_usage_data.h"
#include "components/user_data_importer/common/imported_bookmark_entry.h"
#include "sql/database.h"
#include "testing/platform_test.h"

// In order to test the Safari import functionality effectively, we store a
// simulated Library directory containing dummy data files in the same
// structure as ~/Library in the Chrome test data directory.
// This function returns the path to that directory.
base::FilePath GetTestSafariLibraryPath(const std::string& suffix) {
  base::FilePath test_dir;
  base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir);

  // Our simulated ~/Library directory
  return
      test_dir.AppendASCII("import").AppendASCII("safari").AppendASCII(suffix);
}

class SafariImporterTest : public PlatformTest {
 public:
  SafariImporter* GetSafariImporter() {
    return GetSafariImporterWithPathSuffix("default");
  }

  SafariImporter* GetSafariImporterWithPathSuffix(const std::string& suffix) {
    base::FilePath test_library_dir = GetTestSafariLibraryPath(suffix);
    CHECK(base::PathExists(test_library_dir));
    return new SafariImporter(test_library_dir);
  }
};

TEST_F(SafariImporterTest, BookmarkImport) {
  // Expected results
  const struct {
    bool in_toolbar;
    GURL url;
    // We store the path with levels of nesting delimited by forward slashes.
    std::u16string path;
    std::u16string title;
  } kImportedBookmarksData[] = {
      {true, GURL("http://www.apple.com/"), u"Toolbar/", u"Apple"},
      {true, GURL("http://www.yahoo.com/"), u"Toolbar/", u"Yahoo!"},
      {true, GURL("http://www.cnn.com/"), u"Toolbar/News", u"CNN"},
      {true, GURL("http://www.nytimes.com/"), u"Toolbar/News",
       u"The New York Times"},
      {false, GURL("http://www.reddit.com/"), std::u16string(),
       u"reddit.com: what's new online!"},
      {false, GURL(), std::u16string(), u"Empty Folder"},
      {false, GURL("http://www.webkit.org/blog/"), std::u16string(),
       u"Surfin' Safari - The WebKit Blog"},
  };

  scoped_refptr<SafariImporter> importer(GetSafariImporter());
  std::vector<user_data_importer::ImportedBookmarkEntry> bookmarks;
  importer->ParseBookmarks(u"Toolbar", &bookmarks);
  size_t num_bookmarks = bookmarks.size();
  ASSERT_EQ(std::size(kImportedBookmarksData), num_bookmarks);

  for (size_t i = 0; i < num_bookmarks; ++i) {
    user_data_importer::ImportedBookmarkEntry& entry = bookmarks[i];
    EXPECT_EQ(UNSAFE_TODO(kImportedBookmarksData[i]).in_toolbar,
              entry.in_toolbar);
    EXPECT_EQ(UNSAFE_TODO(kImportedBookmarksData[i]).url, entry.url);

    std::vector<std::u16string> path =
        base::SplitString(UNSAFE_TODO(kImportedBookmarksData[i]).path, u"/",
                          base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
    ASSERT_EQ(path.size(), entry.path.size());
    for (size_t j = 0; j < path.size(); ++j) {
      EXPECT_EQ(path[j], entry.path[j]);
    }

    EXPECT_EQ(UNSAFE_TODO(kImportedBookmarksData[i]).title, entry.title);
  }
}

TEST_F(SafariImporterTest, BookmarkImportWithEmptyBookmarksMenu) {
  // Expected results.
  const struct {
    bool in_toolbar;
    GURL url;
    // We store the path with levels of nesting delimited by forward slashes.
    std::u16string path;
    std::u16string title;
  } kImportedBookmarksData[] = {
      {true, GURL("http://www.apple.com/"), u"Toolbar/", u"Apple"},
      {true, GURL("http://www.yahoo.com/"), u"Toolbar/", u"Yahoo!"},
      {true, GURL("http://www.cnn.com/"), u"Toolbar/News", u"CNN"},
      {true, GURL("http://www.nytimes.com/"), u"Toolbar/News",
       u"The New York Times"},
      {false, GURL("http://www.webkit.org/blog/"), std::u16string(),
       u"Surfin' Safari - The WebKit Blog"},
  };

  scoped_refptr<SafariImporter> importer(
      GetSafariImporterWithPathSuffix("empty_bookmarks_menu"));
  std::vector<user_data_importer::ImportedBookmarkEntry> bookmarks;
  importer->ParseBookmarks(u"Toolbar", &bookmarks);
  size_t num_bookmarks = bookmarks.size();
  ASSERT_EQ(std::size(kImportedBookmarksData), num_bookmarks);

  for (size_t i = 0; i < num_bookmarks; ++i) {
    user_data_importer::ImportedBookmarkEntry& entry = bookmarks[i];
    EXPECT_EQ(UNSAFE_TODO(kImportedBookmarksData[i]).in_toolbar,
              entry.in_toolbar);
    EXPECT_EQ(UNSAFE_TODO(kImportedBookmarksData[i]).url, entry.url);

    std::vector<std::u16string> path =
        base::SplitString(UNSAFE_TODO(kImportedBookmarksData[i]).path, u"/",
                          base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
    ASSERT_EQ(path.size(), entry.path.size());
    for (size_t j = 0; j < path.size(); ++j) {
      EXPECT_EQ(path[j], entry.path[j]);
    }

    EXPECT_EQ(UNSAFE_TODO(kImportedBookmarksData[i]).title, entry.title);
  }
}

TEST_F(SafariImporterTest, CanImport) {
  uint16_t items = user_data_importer::NONE;
  EXPECT_TRUE(SafariImporterCanImport(
      GetTestSafariLibraryPath("default"), &items));
  EXPECT_EQ(items, user_data_importer::FAVORITES);

  // Check that we don't import anything from a bogus library directory.
  base::ScopedTempDir fake_library_dir;
  ASSERT_TRUE(fake_library_dir.CreateUniqueTempDir());
  EXPECT_FALSE(SafariImporterCanImport(fake_library_dir.GetPath(), &items));
}
