text: // 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 <stdint.h>
  
  #include "base/files/file_path.h"
  #include "base/files/scoped_temp_dir.h"
  #include "sql/connection.h"
  #include "sql/statement.h"
  #include "sql/test/sql_test_base.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  namespace {
  
  using SQLMetaTableTest = sql::SQLTestBase;
  
  TEST_F(SQLMetaTableTest, DoesTableExist) {
    EXPECT_FALSE(sql::MetaTable::DoesTableExist(&db()));
  
    {
      sql::MetaTable meta_table;
      EXPECT_TRUE(meta_table.Init(&db(), 1, 1));
    }
  
    EXPECT_TRUE(sql::MetaTable::DoesTableExist(&db()));
  }
  
  TEST_F(SQLMetaTableTest, RazeIfDeprecated) {
    const int kDeprecatedVersion = 1;
    const int kVersion = 2;
  
    // Setup a current database.
    {
      sql::MetaTable meta_table;
      EXPECT_TRUE(meta_table.Init(&db(), kVersion, kVersion));
      EXPECT_TRUE(db().Execute("CREATE TABLE t(c)"));
      EXPECT_TRUE(db().DoesTableExist("t"));
    }
  
    // Table should should still exist if the database version is new enough.
    sql::MetaTable::RazeIfDeprecated(&db(), kDeprecatedVersion);
    EXPECT_TRUE(db().DoesTableExist("t"));
  
    // TODO(shess): It may make sense to Raze() if meta isn't present or
    // version isn't present.  See meta_table.h TODO on RazeIfDeprecated().
  
    // Table should still exist if the version is not available.
    EXPECT_TRUE(db().Execute("DELETE FROM meta WHERE key = 'version'"));
    {
      sql::MetaTable meta_table;
      EXPECT_TRUE(meta_table.Init(&db(), kVersion, kVersion));
      EXPECT_EQ(0, meta_table.GetVersionNumber());
    }
    sql::MetaTable::RazeIfDeprecated(&db(), kDeprecatedVersion);
    EXPECT_TRUE(db().DoesTableExist("t"));
  
    // Table should still exist if meta table is missing.
    EXPECT_TRUE(db().Execute("DROP TABLE meta"));
    sql::MetaTable::RazeIfDeprecated(&db(), kDeprecatedVersion);
    EXPECT_TRUE(db().DoesTableExist("t"));
  
    // Setup meta with deprecated version.
    {
      sql::MetaTable meta_table;
      EXPECT_TRUE(meta_table.Init(&db(), kDeprecatedVersion, kDeprecatedVersion));
    }
  
    // Deprecation check should remove the table.
    EXPECT_TRUE(db().DoesTableExist("t"));
    sql::MetaTable::RazeIfDeprecated(&db(), kDeprecatedVersion);
    EXPECT_FALSE(sql::MetaTable::DoesTableExist(&db()));
    EXPECT_FALSE(db().DoesTableExist("t"));
  }
  
  TEST_F(SQLMetaTableTest, VersionNumber) {
    // Compatibility versions one less than the main versions to make
    // sure the values aren't being crossed with each other.
    const int kVersionFirst = 2;
    const int kCompatVersionFirst = kVersionFirst - 1;
    const int kVersionSecond = 4;
    const int kCompatVersionSecond = kVersionSecond - 1;
    const int kVersionThird = 6;
    const int kCompatVersionThird = kVersionThird - 1;
  
    // First Init() sets the version info as expected.
    {
      sql::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.
    {
      sql::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.
    {
      sql::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) {
    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.
    {
      sql::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.
    {
      sql::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.
    {
      sql::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) {
    const char kKey[] = "Int Key";
    const int kFirstValue = 17;
    const int kSecondValue = 23;
  
    // Initially, the value isn't there until set.
    {
      sql::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.
    {
      sql::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.
    {
      sql::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) {
    const char kKey[] = "Int Key";
    const int64_t kFirstValue = 5000000017LL;
    const int64_t kSecondValue = 5000000023LL;
  
    // Initially, the value isn't there until set.
    {
      sql::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.
    {
      sql::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.
    {
      sql::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) {
    const char kKey[] = "String Key";
    const std::string kValue("String Value");
  
    sql::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
  