text: // Copyright (c) 2011 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 "base/file_util.h"
  #include "base/scoped_temp_dir.h"
  #include "base/stl_util.h"
  #include "base/string_util.h"
  #include "chrome/browser/sessions/session_backend.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  namespace {
  
  typedef std::vector<SessionCommand*> SessionCommands;
  
  struct TestData {
    SessionCommand::id_type command_id;
    std::string data;
  };
  
  SessionCommand* CreateCommandFromData(const TestData& data) {
    SessionCommand* command =
        new SessionCommand(
            data.command_id,
            static_cast<SessionCommand::size_type>(data.data.size()));
    if (!data.data.empty())
      memcpy(command->contents(), data.data.c_str(), data.data.size());
    return command;
  }
  
  }  // namespace
  
  class SessionBackendTest : public testing::Test {
   protected:
    virtual void SetUp() {
      ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
      path_ = temp_dir_.path().Append(FILE_PATH_LITERAL("SessionTestDirs"));
      file_util::CreateDirectory(path_);
    }
  
    void AssertCommandEqualsData(const TestData& data, SessionCommand* command) {
      EXPECT_EQ(data.command_id, command->id());
      EXPECT_EQ(data.data.size(), command->size());
      EXPECT_TRUE(
          memcmp(command->contents(), data.data.c_str(), command->size()) == 0);
    }
  
    // Path used in testing.
    FilePath path_;
    ScopedTempDir temp_dir_;
  };
  
  TEST_F(SessionBackendTest, SimpleReadWrite) {
    scoped_refptr<SessionBackend> backend(
        new SessionBackend(BaseSessionService::SESSION_RESTORE, path_));
    struct TestData data = { 1,  "a" };
    std::vector<SessionCommand*> commands;
    commands.push_back(CreateCommandFromData(data));
    backend->AppendCommands(new SessionCommands(commands), false);
    commands.clear();
  
    // Read it back in.
    backend = NULL;
    backend = new SessionBackend(BaseSessionService::SESSION_RESTORE, path_);
    backend->ReadLastSessionCommandsImpl(&commands);
  
    ASSERT_EQ(1U, commands.size());
    AssertCommandEqualsData(data, commands[0]);
  
    STLDeleteElements(&commands);
  
    backend = NULL;
    backend = new SessionBackend(BaseSessionService::SESSION_RESTORE, path_);
    backend->ReadLastSessionCommandsImpl(&commands);
  
    ASSERT_EQ(0U, commands.size());
  
    // Make sure we can delete.
    backend->DeleteLastSession();
    backend->ReadLastSessionCommandsImpl(&commands);
    ASSERT_EQ(0U, commands.size());
  }
  
  TEST_F(SessionBackendTest, RandomData) {
    struct TestData data[] = {
      { 1,  "a" },
      { 2,  "ab" },
      { 3,  "abc" },
      { 4,  "abcd" },
      { 5,  "abcde" },
      { 6,  "abcdef" },
      { 7,  "abcdefg" },
      { 8,  "abcdefgh" },
      { 9,  "abcdefghi" },
      { 10, "abcdefghij" },
      { 11, "abcdefghijk" },
      { 12, "abcdefghijkl" },
      { 13, "abcdefghijklm" },
    };
  
    for (size_t i = 0; i < arraysize(data); ++i) {
      scoped_refptr<SessionBackend> backend(
          new SessionBackend(BaseSessionService::SESSION_RESTORE, path_));
      std::vector<SessionCommand*> commands;
      if (i != 0) {
        // Read previous data.
        backend->ReadLastSessionCommandsImpl(&commands);
        ASSERT_EQ(i, commands.size());
        for (std::vector<SessionCommand*>::iterator j = commands.begin();
             j != commands.end(); ++j) {
          AssertCommandEqualsData(data[j - commands.begin()], *j);
        }
        backend->AppendCommands(new SessionCommands(commands), false);
        commands.clear();
      }
      commands.push_back(CreateCommandFromData(data[i]));
      backend->AppendCommands(new SessionCommands(commands), false);
    }
  }
  
  TEST_F(SessionBackendTest, BigData) {
    struct TestData data[] = {
      { 1,  "a" },
      { 2,  "ab" },
    };
  
    scoped_refptr<SessionBackend> backend(
        new SessionBackend(BaseSessionService::SESSION_RESTORE, path_));
    std::vector<SessionCommand*> commands;
    commands.push_back(CreateCommandFromData(data[0]));
    const SessionCommand::size_type big_size =
        SessionBackend::kFileReadBufferSize + 100;
    const SessionCommand::id_type big_id = 50;
    SessionCommand* big_command = new SessionCommand(big_id, big_size);
    reinterpret_cast<char*>(big_command->contents())[0] = 'a';
    reinterpret_cast<char*>(big_command->contents())[big_size - 1] = 'z';
    commands.push_back(big_command);
    commands.push_back(CreateCommandFromData(data[1]));
    backend->AppendCommands(new SessionCommands(commands), false);
    commands.clear();
  
    backend = NULL;
    backend = new SessionBackend(BaseSessionService::SESSION_RESTORE, path_);
    commands.clear();
    backend->ReadLastSessionCommandsImpl(&commands);
    ASSERT_EQ(3U, commands.size());
    AssertCommandEqualsData(data[0], commands[0]);
    AssertCommandEqualsData(data[1], commands[2]);
  
    EXPECT_EQ(big_id, commands[1]->id());
    ASSERT_EQ(big_size, commands[1]->size());
    EXPECT_EQ('a', reinterpret_cast<char*>(commands[1]->contents())[0]);
    EXPECT_EQ('z',
              reinterpret_cast<char*>(commands[1]->contents())[big_size - 1]);
    STLDeleteElements(&commands);
  }
  
  TEST_F(SessionBackendTest, EmptyCommand) {
    TestData empty_command;
    empty_command.command_id = 1;
    scoped_refptr<SessionBackend> backend(
        new SessionBackend(BaseSessionService::SESSION_RESTORE, path_));
    std::vector<SessionCommand*>* empty_commands =
        new std::vector<SessionCommand*>();
    empty_commands->push_back(CreateCommandFromData(empty_command));
    backend->AppendCommands(empty_commands, true);
    backend->MoveCurrentSessionToLastSession();
  
    std::vector<SessionCommand*> commands;
    backend->ReadLastSessionCommandsImpl(&commands);
    ASSERT_EQ(1U, commands.size());
    AssertCommandEqualsData(empty_command, commands[0]);
    STLDeleteElements(&commands);
  }
  
  // Writes a command, appends another command with reset to true, then reads
  // making sure we only get back the second command.
  TEST_F(SessionBackendTest, Truncate) {
    scoped_refptr<SessionBackend> backend(
        new SessionBackend(BaseSessionService::SESSION_RESTORE, path_));
    struct TestData first_data = { 1,  "a" };
    std::vector<SessionCommand*> commands;
    commands.push_back(CreateCommandFromData(first_data));
    backend->AppendCommands(new SessionCommands(commands), false);
    commands.clear();
  
    // Write another command, this time resetting the file when appending.
    struct TestData second_data = { 2,  "b" };
    commands.push_back(CreateCommandFromData(second_data));
    backend->AppendCommands(new SessionCommands(commands), true);
    commands.clear();
  
    // Read it back in.
    backend = NULL;
    backend = new SessionBackend(BaseSessionService::SESSION_RESTORE, path_);
    backend->ReadLastSessionCommandsImpl(&commands);
  
    // And make sure we get back the expected data.
    ASSERT_EQ(1U, commands.size());
    AssertCommandEqualsData(second_data, commands[0]);
  
    STLDeleteElements(&commands);
  }
  