#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "sql/database.h"
#include <stddef.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/containers/contains.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/sequence_checker.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/test/bind.h"
#include "base/test/gtest_util.h"
#include "base/test/task_environment.h"
#include "base/thread_annotations.h"
#include "base/trace_event/memory_dump_request_args.h"
#include "base/trace_event/process_memory_dump.h"
#include "build/build_config.h"
#include "sql/database_memory_dump_provider.h"
#include "sql/meta_table.h"
#include "sql/recovery.h"
#include "sql/statement.h"
#include "sql/statement_id.h"
#include "sql/test/scoped_error_expecter.h"
#include "sql/test/test_helpers.h"
#include "sql/transaction.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/sqlite/sqlite3.h"
#if BUILDFLAG(IS_WIN)
#include "base/strings/strcat.h"
#endif
namespace sql {
namespace {
ExecuteWithResult;
int SqliteSchemaCount(Database* db) { … }
void RazeErrorCallback(Database* db,
int expected_error,
int error,
Statement* stmt) { … }
#if BUILDFLAG(IS_POSIX)
class ScopedUmaskSetter { … };
#endif
bool IsOpenedInCorrectJournalMode(Database* db, bool is_wal) { … }
}
class SQLDatabaseTest : public testing::Test,
public testing::WithParamInterface<bool> { … };
TEST_P(SQLDatabaseTest, Execute_ValidStatement) { … }
TEST_P(SQLDatabaseTest, Execute_InvalidStatement) { … }
TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_OneLineValid) { … }
TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_OneLineInvalid) { … }
TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_ExtraContents) { … }
TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_MultipleValidLines) { … }
TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_StopsOnCompileError) { … }
TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_StopsOnStepError) { … }
TEST_P(SQLDatabaseTest, CachedStatement) { … }
TEST_P(SQLDatabaseTest, IsSQLValidTest) { … }
TEST_P(SQLDatabaseTest, DoesTableExist) { … }
TEST_P(SQLDatabaseTest, DoesIndexExist) { … }
TEST_P(SQLDatabaseTest, DoesViewExist) { … }
TEST_P(SQLDatabaseTest, DoesColumnExist) { … }
TEST_P(SQLDatabaseTest, GetLastInsertRowId) { … }
TEST_P(SQLDatabaseTest, ScopedErrorExpecter) { … }
TEST_P(SQLDatabaseTest, SchemaIntrospectionUsesErrorExpecter) { … }
TEST_P(SQLDatabaseTest, SetErrorCallback) { … }
TEST_P(SQLDatabaseTest, SetErrorCallbackDchecksOnExistingCallback) { … }
TEST_P(SQLDatabaseTest, ResetErrorCallback) { … }
TEST_P(SQLDatabaseTest, ErrorCallbackThatClosesDb) { … }
TEST_P(SQLDatabaseTest, DetachFromSequence) { … }
TEST_P(SQLDatabaseTest, ErrorCallbackThatFreesDatabase) { … }
class LifeTracker { … };
TEST_P(SQLDatabaseTest, ErrorCallbackStorageProtectedWhileRun) { … }
TEST_P(SQLDatabaseTest, Execute_CompilationError) { … }
TEST_P(SQLDatabaseTest, GetUniqueStatement_CompilationError) { … }
TEST_P(SQLDatabaseTest, GetCachedStatement_CompilationError) { … }
TEST_P(SQLDatabaseTest, GetUniqueStatement_ExtraContents) { … }
TEST_P(SQLDatabaseTest, GetCachedStatement_ExtraContents) { … }
TEST_P(SQLDatabaseTest, IsSQLValid_ExtraContents) { … }
TEST_P(SQLDatabaseTest, GetUniqueStatement_NoContents) { … }
TEST_P(SQLDatabaseTest, GetCachedStatement_NoContents) { … }
TEST_P(SQLDatabaseTest, GetReadonlyStatement) { … }
TEST_P(SQLDatabaseTest, IsSQLValid_NoContents) { … }
TEST_P(SQLDatabaseTest, Raze) { … }
TEST_P(SQLDatabaseTest, RazeDuringSelect) { … }
void TestPageSize(const base::FilePath& db_prefix,
int initial_page_size,
const std::string& expected_initial_page_size,
int final_page_size,
const std::string& expected_final_page_size) { … }
TEST_P(SQLDatabaseTest, RazePageSize) { … }
TEST_P(SQLDatabaseTest, RazeMultiple) { … }
TEST_P(SQLDatabaseTest, Raze_OtherConnectionHasWriteLock) { … }
TEST_P(SQLDatabaseTest, Raze_OtherConnectionHasReadLock) { … }
TEST_P(SQLDatabaseTest, Raze_EmptyDatabaseFile) { … }
TEST_P(SQLDatabaseTest, RazeNOTADB) { … }
TEST_P(SQLDatabaseTest, RazeNOTADB2) { … }
TEST_P(SQLDatabaseTest, RazeCallbackReopen) { … }
TEST_P(SQLDatabaseTest, RazeAndPoison_DeletesData) { … }
TEST_P(SQLDatabaseTest, RazeAndPoison_IsOpen) { … }
TEST_P(SQLDatabaseTest, RazeAndPoison_Reopen_NoChanges) { … }
TEST_P(SQLDatabaseTest, RazeAndPoison_OpenTransaction) { … }
TEST_P(SQLDatabaseTest, RazeAndPoison_Preload_NoCrash) { … }
TEST_P(SQLDatabaseTest, RazeAndPoison_DoesTableExist) { … }
TEST_P(SQLDatabaseTest, RazeAndPoison_IsSQLValid) { … }
TEST_P(SQLDatabaseTest, RazeAndPoison_Execute) { … }
TEST_P(SQLDatabaseTest, RazeAndPoison_GetUniqueStatement) { … }
TEST_P(SQLDatabaseTest, RazeAndPoison_GetCachedStatement) { … }
TEST_P(SQLDatabaseTest, RazeAndPoison_InvalidatesUniqueStatement) { … }
TEST_P(SQLDatabaseTest, RazeAndPoison_InvalidatesCachedStatement) { … }
TEST_P(SQLDatabaseTest, RazeAndPoison_TransactionBegin) { … }
TEST_P(SQLDatabaseTest, Close_IsSQLValid) { … }
TEST_P(SQLDatabaseTest, RazeTruncate) { … }
#if BUILDFLAG(IS_ANDROID)
TEST_P(SQLDatabaseTest, SetTempDirForSQL) {
MetaTable meta_table;
ASSERT_TRUE(meta_table.Init(db_.get(), 4, 4));
}
#endif
TEST_P(SQLDatabaseTest, Delete) { … }
#if BUILDFLAG(IS_POSIX)
TEST_P(SQLDatabaseTest, PosixFilePermissions) { … }
#endif
TEST_P(SQLDatabaseTest, Poison_IsOpen) { … }
TEST_P(SQLDatabaseTest, Poison_Close_Reopen_NoChanges) { … }
TEST_P(SQLDatabaseTest, Poison_Preload_NoCrash) { … }
TEST_P(SQLDatabaseTest, Poison_DoesTableExist) { … }
TEST_P(SQLDatabaseTest, Poison_IsSQLValid) { … }
TEST_P(SQLDatabaseTest, Poison_Execute) { … }
TEST_P(SQLDatabaseTest, Poison_GetUniqueStatement) { … }
TEST_P(SQLDatabaseTest, Poison_GetCachedStatement) { … }
TEST_P(SQLDatabaseTest, Poison_InvalidatesUniqueStatement) { … }
TEST_P(SQLDatabaseTest, Poison_InvalidatesCachedStatement) { … }
TEST_P(SQLDatabaseTest, Poison_TransactionBegin) { … }
TEST_P(SQLDatabaseTest, Poison_OpenTransaction) { … }
TEST_P(SQLDatabaseTest, AttachDatabase) { … }
TEST_P(SQLDatabaseTest, AttachDatabaseWithOpenTransaction) { … }
TEST_P(SQLDatabaseTest, FullIntegrityCheck) { … }
TEST_P(SQLDatabaseTest, OnMemoryDump) { … }
TEST_P(SQLDatabaseTest, CollectDiagnosticInfo) { … }
TEST_P(SQLDatabaseTest, MmapInitiallyEnabled) { … }
TEST_P(SQLDatabaseTest, MmapInitiallyEnabledAltStatus) { … }
TEST_P(SQLDatabaseTest, ComputeMmapSizeForOpen) { … }
TEST_P(SQLDatabaseTest, ComputeMmapSizeForOpenAltStatus) { … }
TEST_P(SQLDatabaseTest, GetMemoryUsage) { … }
TEST_P(SQLDatabaseTest, DoubleQuotedStringLiteralsDisabledByDefault) { … }
TEST_P(SQLDatabaseTest, ForeignKeyEnforcementDisabledByDefault) { … }
TEST_P(SQLDatabaseTest, TriggersDisabledByDefault) { … }
TEST_P(SQLDatabaseTest, ReOpenWithDifferentJournalMode) { … }
#if BUILDFLAG(IS_WIN)
class SQLDatabaseTestExclusiveFileLockMode
: public testing::Test,
public testing::WithParamInterface<::testing::tuple<bool, bool>> {
public:
~SQLDatabaseTestExclusiveFileLockMode() override = default;
void SetUp() override {
db_ = std::make_unique<Database>(GetDBOptions());
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
db_path_ = temp_dir_.GetPath().AppendASCII("maybelocked.sqlite");
ASSERT_TRUE(db_->Open(db_path_));
}
DatabaseOptions GetDBOptions() {
DatabaseOptions options;
options.wal_mode = IsWALEnabled();
options.exclusive_locking = true;
options.exclusive_database_file_lock = IsExclusivelockEnabled();
return options;
}
bool IsWALEnabled() { return std::get<0>(GetParam()); }
bool IsExclusivelockEnabled() { return std::get<1>(GetParam()); }
protected:
base::ScopedTempDir temp_dir_;
base::FilePath db_path_;
std::unique_ptr<Database> db_;
};
TEST_P(SQLDatabaseTestExclusiveFileLockMode, BasicStatement) {
ASSERT_TRUE(db_->Execute("CREATE TABLE data(contents TEXT)"));
EXPECT_EQ(SQLITE_OK, db_->GetErrorCode());
ASSERT_TRUE(base::PathExists(db_path_));
base::File open_db(db_path_, base::File::Flags::FLAG_OPEN_ALWAYS |
base::File::Flags::FLAG_READ);
EXPECT_EQ(IsExclusivelockEnabled(), !open_db.IsValid());
}
INSTANTIATE_TEST_SUITE_P(
All,
SQLDatabaseTestExclusiveFileLockMode,
::testing::Combine(::testing::Bool(), ::testing::Bool()),
[](const auto& info) {
return base::StrCat(
{std::get<0>(info.param) ? "WALEnabled" : "WALDisabled",
std::get<1>(info.param) ? "ExclusiveLock" : "NoExclusiveLock"});
});
#else
TEST(SQLInvalidDatabaseFlagsDeathTest, ExclusiveDatabaseLock) { … }
#endif
class SQLDatabaseTestExclusiveMode : public testing::Test,
public testing::WithParamInterface<bool> { … };
TEST_P(SQLDatabaseTestExclusiveMode, LockingModeExclusive) { … }
TEST_P(SQLDatabaseTest, LockingModeNormal) { … }
TEST_P(SQLDatabaseTest, OpenedInCorrectMode) { … }
TEST_P(SQLDatabaseTest, CheckpointDatabase) { … }
TEST_P(SQLDatabaseTest, OpenFailsAfterCorruptSizeInHeader) { … }
TEST_P(SQLDatabaseTest, OpenWithRecoveryHandlesCorruption) { … }
TEST_P(SQLDatabaseTest, ExecuteFailsAfterCorruptSizeInHeader) { … }
TEST_P(SQLDatabaseTest, SchemaFailsAfterCorruptSizeInHeader) { … }
TEST(SQLEmptyPathDatabaseTest, EmptyPathTest) { … }
#if !BUILDFLAG(IS_FUCHSIA)
INSTANTIATE_TEST_SUITE_P(…);
INSTANTIATE_TEST_SUITE_P(…);
#else
INSTANTIATE_TEST_SUITE_P(JournalMode, SQLDatabaseTest, testing::Values(false));
INSTANTIATE_TEST_SUITE_P(JournalMode,
SQLDatabaseTestExclusiveMode,
testing::Values(false));
#endif
}