// Copyright 2013 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 "sql/meta_table.h" #include #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" #include "sql/database.h" #include "sql/statement.h" #include "testing/gtest/include/gtest/gtest.h" namespace sql { namespace { class SQLMetaTableTest : public testing::Test { public: ~SQLMetaTableTest() override = default; void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); ASSERT_TRUE( db_.Open(temp_dir_.GetPath().AppendASCII("meta_table_test.sqlite"))); } protected: base::ScopedTempDir temp_dir_; Database db_; }; TEST_F(SQLMetaTableTest, DoesTableExist) { EXPECT_FALSE(MetaTable::DoesTableExist(&db_)); { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); } EXPECT_TRUE(MetaTable::DoesTableExist(&db_)); } TEST_F(SQLMetaTableTest, DeleteTableForTesting) { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); EXPECT_TRUE(MetaTable::DeleteTableForTesting(&db_)); EXPECT_FALSE(MetaTable::DoesTableExist(&db_)); } TEST_F(SQLMetaTableTest, RazeIfIncompatiblePreservesDatabasesWithoutMetadata) { EXPECT_TRUE(db_.Execute("CREATE TABLE data(id INTEGER PRIMARY KEY)")); ASSERT_TRUE(db_.DoesTableExist("data")); // The table should not have been cleared, since the database does not have a // metadata table. MetaTable::RazeIfIncompatible(&db_, 1, /*current_version=*/1); EXPECT_TRUE(db_.DoesTableExist("data")); } TEST_F(SQLMetaTableTest, RazeIfIncompatibleRazesIncompatiblyOldTables) { constexpr int kWrittenVersion = 1; constexpr int kCompatibleVersion = 1; // Setup a current database. { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, kWrittenVersion, kCompatibleVersion)); EXPECT_TRUE(db_.Execute("CREATE TABLE data(id INTEGER PRIMARY KEY)")); ASSERT_TRUE(db_.DoesTableExist("data")); } // The table should have been cleared, since the least version compatible with // the written database is greater than the current version. MetaTable::RazeIfIncompatible(&db_, kWrittenVersion + 1, /*current_version=*/kWrittenVersion + 1); EXPECT_FALSE(db_.DoesTableExist("data")); } TEST_F(SQLMetaTableTest, RazeIfIncompatibleRazesIncompatiblyNewTables) { constexpr int kCompatibleVersion = 2; constexpr int kWrittenVersion = 3; // Setup a current database. { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, kWrittenVersion, kCompatibleVersion)); EXPECT_TRUE(db_.Execute("CREATE TABLE data(id INTEGER PRIMARY KEY)")); ASSERT_TRUE(db_.DoesTableExist("data")); } // The table should have been cleared, since the least version compatible with // the written database is greater than the current version. MetaTable::RazeIfIncompatible(&db_, MetaTable::kNoLowestSupportedVersion, /*current_version=*/kCompatibleVersion - 1); EXPECT_FALSE(db_.DoesTableExist("data")); } TEST_F(SQLMetaTableTest, RazeIfIncompatibleDoesntRazeWhenItShouldnt) { constexpr int kVersion = 2; { MetaTable meta_table; EXPECT_TRUE( meta_table.Init(&db_, kVersion, /*compatible_version=*/kVersion - 1)); EXPECT_TRUE(db_.Execute("CREATE TABLE data(id INTEGER PRIMARY KEY)")); EXPECT_TRUE(db_.DoesTableExist("data")); } MetaTable::RazeIfIncompatible(&db_, kVersion, /*current_version=*/kVersion); EXPECT_TRUE(db_.DoesTableExist("data")) << "Table should still exist if the database version is exactly right."; MetaTable::RazeIfIncompatible(&db_, kVersion - 1, /*current_version=*/kVersion); EXPECT_TRUE(db_.DoesTableExist("data")) << "... or if the lower bound is less than the actual version"; MetaTable::RazeIfIncompatible(&db_, MetaTable::kNoLowestSupportedVersion, /*current_version=*/kVersion); EXPECT_TRUE(db_.DoesTableExist("data")) << "... or if the lower bound is not set"; MetaTable::RazeIfIncompatible(&db_, MetaTable::kNoLowestSupportedVersion, /*current_version=*/kVersion - 1); EXPECT_TRUE(db_.DoesTableExist("data")) << "... even if the current version exactly matches the written " "database's least compatible version."; } TEST_F(SQLMetaTableTest, VersionNumber) { // Compatibility versions one less than the main versions to make // sure the values aren't being crossed with each other. constexpr int kVersionFirst = 2; constexpr int kCompatVersionFirst = kVersionFirst - 1; constexpr int kVersionSecond = 4; constexpr int kCompatVersionSecond = kVersionSecond - 1; constexpr int kVersionThird = 6; constexpr int kCompatVersionThird = kVersionThird - 1; // First Init() sets the version info as expected. { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, kVersionFirst, kCompatVersionFirst)); EXPECT_EQ(kVersionFirst, meta_table.GetVersionNumber()); EXPECT_EQ(kCompatVersionFirst, meta_table.GetCompatibleVersionNumber()); } // Second Init() does not change the version info. { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, kVersionSecond, kCompatVersionSecond)); EXPECT_EQ(kVersionFirst, meta_table.GetVersionNumber()); EXPECT_EQ(kCompatVersionFirst, meta_table.GetCompatibleVersionNumber()); meta_table.SetVersionNumber(kVersionSecond); meta_table.SetCompatibleVersionNumber(kCompatVersionSecond); } // Version info from Set*() calls is seen. { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, kVersionThird, kCompatVersionThird)); EXPECT_EQ(kVersionSecond, meta_table.GetVersionNumber()); EXPECT_EQ(kCompatVersionSecond, meta_table.GetCompatibleVersionNumber()); } } TEST_F(SQLMetaTableTest, StringValue) { static const char kKey[] = "String Key"; const std::string kFirstValue("First Value"); const std::string kSecondValue("Second Value"); // Initially, the value isn't there until set. { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); std::string value; EXPECT_FALSE(meta_table.GetValue(kKey, &value)); EXPECT_TRUE(meta_table.SetValue(kKey, kFirstValue)); EXPECT_TRUE(meta_table.GetValue(kKey, &value)); EXPECT_EQ(kFirstValue, value); } // Value is persistent across different instances. { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); std::string value; EXPECT_TRUE(meta_table.GetValue(kKey, &value)); EXPECT_EQ(kFirstValue, value); EXPECT_TRUE(meta_table.SetValue(kKey, kSecondValue)); } // Existing value was successfully changed. { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); std::string value; EXPECT_TRUE(meta_table.GetValue(kKey, &value)); EXPECT_EQ(kSecondValue, value); } } TEST_F(SQLMetaTableTest, IntValue) { static const char kKey[] = "Int Key"; constexpr int kFirstValue = 17; constexpr int kSecondValue = 23; // Initially, the value isn't there until set. { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); int value; EXPECT_FALSE(meta_table.GetValue(kKey, &value)); EXPECT_TRUE(meta_table.SetValue(kKey, kFirstValue)); EXPECT_TRUE(meta_table.GetValue(kKey, &value)); EXPECT_EQ(kFirstValue, value); } // Value is persistent across different instances. { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); int value; EXPECT_TRUE(meta_table.GetValue(kKey, &value)); EXPECT_EQ(kFirstValue, value); EXPECT_TRUE(meta_table.SetValue(kKey, kSecondValue)); } // Existing value was successfully changed. { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); int value; EXPECT_TRUE(meta_table.GetValue(kKey, &value)); EXPECT_EQ(kSecondValue, value); } } TEST_F(SQLMetaTableTest, Int64Value) { static const char kKey[] = "Int Key"; const int64_t kFirstValue = 5000000017LL; const int64_t kSecondValue = 5000000023LL; // Initially, the value isn't there until set. { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); int64_t value; EXPECT_FALSE(meta_table.GetValue(kKey, &value)); EXPECT_TRUE(meta_table.SetValue(kKey, kFirstValue)); EXPECT_TRUE(meta_table.GetValue(kKey, &value)); EXPECT_EQ(kFirstValue, value); } // Value is persistent across different instances. { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); int64_t value; EXPECT_TRUE(meta_table.GetValue(kKey, &value)); EXPECT_EQ(kFirstValue, value); EXPECT_TRUE(meta_table.SetValue(kKey, kSecondValue)); } // Existing value was successfully changed. { MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); int64_t value; EXPECT_TRUE(meta_table.GetValue(kKey, &value)); EXPECT_EQ(kSecondValue, value); } } TEST_F(SQLMetaTableTest, DeleteKey) { static const char kKey[] = "String Key"; const std::string kValue("String Value"); MetaTable meta_table; EXPECT_TRUE(meta_table.Init(&db_, 1, 1)); // Value isn't present. std::string value; EXPECT_FALSE(meta_table.GetValue(kKey, &value)); // Now value is present. EXPECT_TRUE(meta_table.SetValue(kKey, kValue)); EXPECT_TRUE(meta_table.GetValue(kKey, &value)); EXPECT_EQ(kValue, value); // After delete value isn't present. EXPECT_TRUE(meta_table.DeleteKey(kKey)); EXPECT_FALSE(meta_table.GetValue(kKey, &value)); } } // namespace } // namespace sql