1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/files/file_util.h"
6#include "base/files/scoped_temp_dir.h"
7#include "base/stl_util.h"
8#include "base/strings/string_util.h"
9#include "chrome/browser/sessions/session_backend.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12namespace {
13
14typedef std::vector<SessionCommand*> SessionCommands;
15
16struct TestData {
17  SessionCommand::id_type command_id;
18  std::string data;
19};
20
21SessionCommand* CreateCommandFromData(const TestData& data) {
22  SessionCommand* command =
23      new SessionCommand(
24          data.command_id,
25          static_cast<SessionCommand::size_type>(data.data.size()));
26  if (!data.data.empty())
27    memcpy(command->contents(), data.data.c_str(), data.data.size());
28  return command;
29}
30
31}  // namespace
32
33class SessionBackendTest : public testing::Test {
34 protected:
35  virtual void SetUp() {
36    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
37    path_ = temp_dir_.path().Append(FILE_PATH_LITERAL("SessionTestDirs"));
38    base::CreateDirectory(path_);
39  }
40
41  void AssertCommandEqualsData(const TestData& data, SessionCommand* command) {
42    EXPECT_EQ(data.command_id, command->id());
43    EXPECT_EQ(data.data.size(), command->size());
44    EXPECT_TRUE(
45        memcmp(command->contents(), data.data.c_str(), command->size()) == 0);
46  }
47
48  // Path used in testing.
49  base::FilePath path_;
50  base::ScopedTempDir temp_dir_;
51};
52
53TEST_F(SessionBackendTest, SimpleReadWrite) {
54  scoped_refptr<SessionBackend> backend(
55      new SessionBackend(BaseSessionService::SESSION_RESTORE, path_));
56  struct TestData data = { 1,  "a" };
57  std::vector<SessionCommand*> commands;
58  commands.push_back(CreateCommandFromData(data));
59  backend->AppendCommands(new SessionCommands(commands), false);
60  commands.clear();
61
62  // Read it back in.
63  backend = NULL;
64  backend = new SessionBackend(BaseSessionService::SESSION_RESTORE, path_);
65  backend->ReadLastSessionCommandsImpl(&commands);
66
67  ASSERT_EQ(1U, commands.size());
68  AssertCommandEqualsData(data, commands[0]);
69
70  STLDeleteElements(&commands);
71
72  backend = NULL;
73  backend = new SessionBackend(BaseSessionService::SESSION_RESTORE, path_);
74  backend->ReadLastSessionCommandsImpl(&commands);
75
76  ASSERT_EQ(0U, commands.size());
77
78  // Make sure we can delete.
79  backend->DeleteLastSession();
80  backend->ReadLastSessionCommandsImpl(&commands);
81  ASSERT_EQ(0U, commands.size());
82}
83
84TEST_F(SessionBackendTest, RandomData) {
85  struct TestData data[] = {
86    { 1,  "a" },
87    { 2,  "ab" },
88    { 3,  "abc" },
89    { 4,  "abcd" },
90    { 5,  "abcde" },
91    { 6,  "abcdef" },
92    { 7,  "abcdefg" },
93    { 8,  "abcdefgh" },
94    { 9,  "abcdefghi" },
95    { 10, "abcdefghij" },
96    { 11, "abcdefghijk" },
97    { 12, "abcdefghijkl" },
98    { 13, "abcdefghijklm" },
99  };
100
101  for (size_t i = 0; i < arraysize(data); ++i) {
102    scoped_refptr<SessionBackend> backend(
103        new SessionBackend(BaseSessionService::SESSION_RESTORE, path_));
104    std::vector<SessionCommand*> commands;
105    if (i != 0) {
106      // Read previous data.
107      backend->ReadLastSessionCommandsImpl(&commands);
108      ASSERT_EQ(i, commands.size());
109      for (std::vector<SessionCommand*>::iterator j = commands.begin();
110           j != commands.end(); ++j) {
111        AssertCommandEqualsData(data[j - commands.begin()], *j);
112      }
113      backend->AppendCommands(new SessionCommands(commands), false);
114      commands.clear();
115    }
116    commands.push_back(CreateCommandFromData(data[i]));
117    backend->AppendCommands(new SessionCommands(commands), false);
118  }
119}
120
121TEST_F(SessionBackendTest, BigData) {
122  struct TestData data[] = {
123    { 1,  "a" },
124    { 2,  "ab" },
125  };
126
127  scoped_refptr<SessionBackend> backend(
128      new SessionBackend(BaseSessionService::SESSION_RESTORE, path_));
129  std::vector<SessionCommand*> commands;
130  commands.push_back(CreateCommandFromData(data[0]));
131  const SessionCommand::size_type big_size =
132      SessionBackend::kFileReadBufferSize + 100;
133  const SessionCommand::id_type big_id = 50;
134  SessionCommand* big_command = new SessionCommand(big_id, big_size);
135  reinterpret_cast<char*>(big_command->contents())[0] = 'a';
136  reinterpret_cast<char*>(big_command->contents())[big_size - 1] = 'z';
137  commands.push_back(big_command);
138  commands.push_back(CreateCommandFromData(data[1]));
139  backend->AppendCommands(new SessionCommands(commands), false);
140  commands.clear();
141
142  backend = NULL;
143  backend = new SessionBackend(BaseSessionService::SESSION_RESTORE, path_);
144  commands.clear();
145  backend->ReadLastSessionCommandsImpl(&commands);
146  ASSERT_EQ(3U, commands.size());
147  AssertCommandEqualsData(data[0], commands[0]);
148  AssertCommandEqualsData(data[1], commands[2]);
149
150  EXPECT_EQ(big_id, commands[1]->id());
151  ASSERT_EQ(big_size, commands[1]->size());
152  EXPECT_EQ('a', reinterpret_cast<char*>(commands[1]->contents())[0]);
153  EXPECT_EQ('z',
154            reinterpret_cast<char*>(commands[1]->contents())[big_size - 1]);
155  STLDeleteElements(&commands);
156}
157
158TEST_F(SessionBackendTest, EmptyCommand) {
159  TestData empty_command;
160  empty_command.command_id = 1;
161  scoped_refptr<SessionBackend> backend(
162      new SessionBackend(BaseSessionService::SESSION_RESTORE, path_));
163  std::vector<SessionCommand*>* empty_commands =
164      new std::vector<SessionCommand*>();
165  empty_commands->push_back(CreateCommandFromData(empty_command));
166  backend->AppendCommands(empty_commands, true);
167  backend->MoveCurrentSessionToLastSession();
168
169  std::vector<SessionCommand*> commands;
170  backend->ReadLastSessionCommandsImpl(&commands);
171  ASSERT_EQ(1U, commands.size());
172  AssertCommandEqualsData(empty_command, commands[0]);
173  STLDeleteElements(&commands);
174}
175
176// Writes a command, appends another command with reset to true, then reads
177// making sure we only get back the second command.
178TEST_F(SessionBackendTest, Truncate) {
179  scoped_refptr<SessionBackend> backend(
180      new SessionBackend(BaseSessionService::SESSION_RESTORE, path_));
181  struct TestData first_data = { 1,  "a" };
182  std::vector<SessionCommand*> commands;
183  commands.push_back(CreateCommandFromData(first_data));
184  backend->AppendCommands(new SessionCommands(commands), false);
185  commands.clear();
186
187  // Write another command, this time resetting the file when appending.
188  struct TestData second_data = { 2,  "b" };
189  commands.push_back(CreateCommandFromData(second_data));
190  backend->AppendCommands(new SessionCommands(commands), true);
191  commands.clear();
192
193  // Read it back in.
194  backend = NULL;
195  backend = new SessionBackend(BaseSessionService::SESSION_RESTORE, path_);
196  backend->ReadLastSessionCommandsImpl(&commands);
197
198  // And make sure we get back the expected data.
199  ASSERT_EQ(1U, commands.size());
200  AssertCommandEqualsData(second_data, commands[0]);
201
202  STLDeleteElements(&commands);
203}
204