chromium/sql/test/test_helpers.h

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SQL_TEST_TEST_HELPERS_H_
#define SQL_TEST_TEST_HELPERS_H_

#include <stddef.h>
#include <stdint.h>

#include <optional>
#include <string>
#include <string_view>

#include "base/strings/cstring_view.h"

// Collection of test-only convenience functions.

namespace base {
class FilePath;
}

namespace sql {
class Database;
}

namespace sql::test {

// Read a database's page size. Returns nullopt in case of error.
std::optional<int> ReadDatabasePageSize(const base::FilePath& db_path);

// SQLite stores the database size in the header, and if the actual
// OS-derived size is smaller, the database is considered corrupt.
// [This case is actually a common form of corruption in the wild.]
// This helper sets the in-header size to one page larger than the
// actual file size.  The resulting file will return SQLITE_CORRUPT
// for most operations unless PRAGMA writable_schema is turned ON.
//
// This function operates on the raw database file, outstanding database
// connections may not see the change because of the database cache.  See
// CorruptSizeInHeaderWithLock().
//
// Returns false if any error occurs accessing the file.
[[nodiscard]] bool CorruptSizeInHeader(const base::FilePath& db_path);

// Call CorruptSizeInHeader() while holding a SQLite-compatible lock
// on the database.  This can be used to corrupt a database which is
// already open elsewhere.  Blocks until a write lock can be acquired.
[[nodiscard]] bool CorruptSizeInHeaderWithLock(const base::FilePath& db_path);

// Simulates total index corruption by zeroing the root page of an index B-tree.
//
// The corrupted database will still open successfully. SELECTs on the table
// associated with the index will work, as long as they don't access the index.
// However, any query that accesses the index will fail with SQLITE_CORRUPT.
// DROPping the table or the index will fail.
[[nodiscard]] bool CorruptIndexRootPage(const base::FilePath& db_path,
                                        std::string_view index_name);

// Return the number of tables in sqlite_schema.
[[nodiscard]] size_t CountSQLTables(sql::Database* db);

// Return the number of indices in sqlite_schema.
[[nodiscard]] size_t CountSQLIndices(sql::Database* db);

// Returns the number of columns in the named table.  0 indicates an
// error (probably no such table).
[[nodiscard]] size_t CountTableColumns(sql::Database* db, const char* table);

// Sets |*count| to the number of rows in |table|.  Returns false in
// case of error, such as the table not existing.
bool CountTableRows(sql::Database* db, const char* table, size_t* count);

// Creates a SQLite database at |db_path| from the sqlite .dump output
// at |sql_path|.  Returns false if |db_path| already exists, or if
// sql_path does not exist or cannot be read, or if there is an error
// executing the statements.
[[nodiscard]] bool CreateDatabaseFromSQL(const base::FilePath& db_path,
                                         const base::FilePath& sql_path);

// Test-friendly wrapper around sql::Database::IntegrityCheck().
[[nodiscard]] std::string IntegrityCheck(sql::Database& db);

// ExecuteWithResult() executes |sql| and returns the first column of the first
// row as a string.  The empty string is returned for no rows.  This makes it
// easier to test simple query results using EXPECT_EQ().  For instance:
//   EXPECT_EQ("1024", ExecuteWithResult(db, "PRAGMA page_size"));
//
// ExecuteWithResults() stringifies a larger result set by putting |column_sep|
// between columns and |row_sep| between rows.  For instance:
//   EXPECT_EQ("1,3,5", ExecuteWithResults(
//       db, "SELECT id FROM t ORDER BY id", "|", ","));
// Note that EXPECT_EQ() can nicely diff when using \n as |row_sep|.
//
// To test NULL, use the COALESCE() function:
//   EXPECT_EQ("<NULL>", ExecuteWithResult(
//       db, "SELECT c || '<NULL>' FROM t WHERE id = 1"));
// To test blobs use the HEX() function.
std::string ExecuteWithResult(sql::Database* db, const base::cstring_view sql);
std::string ExecuteWithResults(sql::Database* db,
                               const base::cstring_view sql,
                               const base::cstring_view column_sep,
                               const base::cstring_view row_sep);

// Returns the database size, in pages. Crashes on SQLite errors.
int GetPageCount(sql::Database* db);

// Column information returned by GetColumnInfo.
//
// C++ wrapper around the out-params of sqlite3_table_column_metadata().
struct ColumnInfo {};

}  // namespace sql::test

#endif  // SQL_TEST_TEST_HELPERS_H_