// 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/memory/scoped_temp_dir.h"
#include "base/stl_util-inl.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);
}