// 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); }