blob: a913352ba3c28f3943131e79f354699eb3bf564f [file] [log] [blame]
[email protected]43ffdd82013-09-10 23:44:501// Copyright 2013 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 "sql/test/test_helpers.h"
6
7#include <string>
8
9#include "base/file_util.h"
10#include "sql/connection.h"
11#include "sql/statement.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14namespace {
15
16size_t CountSQLItemsOfType(sql::Connection* db, const char* type) {
17 const char kTypeSQL[] = "SELECT COUNT(*) FROM sqlite_master WHERE type = ?";
18 sql::Statement s(db->GetUniqueStatement(kTypeSQL));
19 s.BindCString(0, type);
20 EXPECT_TRUE(s.Step());
21 return s.ColumnInt(0);
22}
23
[email protected]a8848a72013-11-18 04:18:4724// Helper for reading a number from the SQLite header.
25// See net/base/big_endian.h.
26unsigned ReadBigEndian(unsigned char* buf, size_t bytes) {
27 unsigned r = buf[0];
28 for (size_t i = 1; i < bytes; i++) {
29 r <<= 8;
30 r |= buf[i];
31 }
32 return r;
33}
34
35// Helper for writing a number to the SQLite header.
36void WriteBigEndian(unsigned val, unsigned char* buf, size_t bytes) {
37 for (size_t i = 0; i < bytes; i++) {
38 buf[bytes - i - 1] = (val & 0xFF);
39 val >>= 8;
40 }
41}
42
[email protected]43ffdd82013-09-10 23:44:5043} // namespace
44
45namespace sql {
46namespace test {
47
[email protected]a8848a72013-11-18 04:18:4748bool CorruptSizeInHeader(const base::FilePath& db_path) {
49 // See http://www.sqlite.org/fileformat.html#database_header
50 const size_t kHeaderSize = 100;
51 const size_t kPageSizeOffset = 16;
52 const size_t kFileChangeCountOffset = 24;
53 const size_t kPageCountOffset = 28;
54 const size_t kVersionValidForOffset = 92; // duplicate kFileChangeCountOffset
55
56 unsigned char header[kHeaderSize];
57
58 file_util::ScopedFILE file(file_util::OpenFile(db_path, "rb+"));
59 if (!file.get())
60 return false;
61
62 if (0 != fseek(file.get(), 0, SEEK_SET))
63 return false;
64 if (1u != fread(header, sizeof(header), 1, file.get()))
65 return false;
66
67 int64 db_size = 0;
[email protected]56285702013-12-04 18:22:4968 if (!base::GetFileSize(db_path, &db_size))
[email protected]a8848a72013-11-18 04:18:4769 return false;
70
71 const unsigned page_size = ReadBigEndian(header + kPageSizeOffset, 2);
72
73 // One larger than the expected size.
74 const unsigned page_count = (db_size + page_size) / page_size;
75 WriteBigEndian(page_count, header + kPageCountOffset, 4);
76
77 // Update change count so outstanding readers know the info changed.
78 // Both spots must match for the page count to be considered valid.
79 unsigned change_count = ReadBigEndian(header + kFileChangeCountOffset, 4);
80 WriteBigEndian(change_count + 1, header + kFileChangeCountOffset, 4);
81 WriteBigEndian(change_count + 1, header + kVersionValidForOffset, 4);
82
83 if (0 != fseek(file.get(), 0, SEEK_SET))
84 return false;
85 if (1u != fwrite(header, sizeof(header), 1, file.get()))
86 return false;
87
88 return true;
89}
90
[email protected]43ffdd82013-09-10 23:44:5091size_t CountSQLTables(sql::Connection* db) {
92 return CountSQLItemsOfType(db, "table");
93}
94
95size_t CountSQLIndices(sql::Connection* db) {
96 return CountSQLItemsOfType(db, "index");
97}
98
99size_t CountTableColumns(sql::Connection* db, const char* table) {
100 // TODO(shess): sql::Connection::QuoteForSQL() would make sense.
101 std::string quoted_table;
102 {
103 const char kQuoteSQL[] = "SELECT quote(?)";
104 sql::Statement s(db->GetUniqueStatement(kQuoteSQL));
105 s.BindCString(0, table);
106 EXPECT_TRUE(s.Step());
107 quoted_table = s.ColumnString(0);
108 }
109
110 std::string sql = "PRAGMA table_info(" + quoted_table + ")";
111 sql::Statement s(db->GetUniqueStatement(sql.c_str()));
112 size_t rows = 0;
113 while (s.Step()) {
114 ++rows;
115 }
116 EXPECT_TRUE(s.Succeeded());
117 return rows;
118}
119
[email protected]fe4e3de2013-10-08 02:19:17120bool CountTableRows(sql::Connection* db, const char* table, size_t* count) {
121 // TODO(shess): Table should probably be quoted with [] or "". See
122 // http://www.sqlite.org/lang_keywords.html . Meanwhile, odd names
123 // will throw an error.
124 std::string sql = "SELECT COUNT(*) FROM ";
125 sql += table;
126 sql::Statement s(db->GetUniqueStatement(sql.c_str()));
127 if (!s.Step())
128 return false;
129
130 *count = s.ColumnInt64(0);
131 return true;
132}
133
[email protected]43ffdd82013-09-10 23:44:50134bool CreateDatabaseFromSQL(const base::FilePath& db_path,
135 const base::FilePath& sql_path) {
136 if (base::PathExists(db_path) || !base::PathExists(sql_path))
137 return false;
138
139 std::string sql;
140 if (!base::ReadFileToString(sql_path, &sql))
141 return false;
142
143 sql::Connection db;
144 if (!db.Open(db_path))
145 return false;
146
[email protected]29a4fd52013-10-16 05:49:05147 // TODO(shess): Android defaults to auto_vacuum mode.
148 // Unfortunately, this makes certain kinds of tests which manipulate
149 // the raw database hard/impossible to write.
150 // http://crbug.com/307303 is for exploring this test issue.
151 ignore_result(db.Execute("PRAGMA auto_vacuum = 0"));
152
[email protected]43ffdd82013-09-10 23:44:50153 return db.Execute(sql.c_str());
154}
155
[email protected]a8848a72013-11-18 04:18:47156std::string IntegrityCheck(sql::Connection* db) {
157 sql::Statement statement(db->GetUniqueStatement("PRAGMA integrity_check"));
158
159 // SQLite should always return a row of data.
160 EXPECT_TRUE(statement.Step());
161
162 return statement.ColumnString(0);
163}
164
[email protected]43ffdd82013-09-10 23:44:50165} // namespace test
166} // namespace sql