#include <gtest/gtest.h>
#include <string>
#include <iostream>
#include <system_error>
#include <util/fs.h>
using std::cout;
using std::endl;
using std::string;
using std::vector;
using std::system_error;
using std::runtime_error;
using fs = scc::util::Filesystem;
struct SqliteTest : public testing::Test
{
string curdir;
Conn db;
SqliteTest()
{
curdir = fs::get_current_dir();
system_error err;
fs::remove_all("sandbox", &err);
fs::create_dir("sandbox");
fs::change_dir("sandbox");
}
virtual ~SqliteTest()
{
fs::change_dir(curdir);
system_error err;
fs::remove_all("sandbox", &err);
}
void reopen(const string& uri)
{
cout << "opening: " << uri << endl;
db.reopen(uri);
}
};
TEST_F(SqliteTest, default_conn)
{
auto fs = fs::scan_dir(".");
cout << "filesystem:" << endl;
for (auto& d : fs)
{
cout << d.first << " " << d.second << endl;
}
ASSERT_EQ(fs.size(), 0);
}
TEST_F(SqliteTest, memory_conn)
{
reopen("file::memory:");
auto fs = fs::scan_dir(".");
cout << "filesystem:" << endl;
for (auto& d : fs)
{
cout << d.first << " " << d.second << endl;
}
ASSERT_EQ(fs.size(), 0);
}
TEST_F(SqliteTest, file_open)
{
reopen("file:dbfile?mode=rwc");
auto fs = fs::scan_dir(".");
cout << "filesystem:" << endl;
for (auto& d : fs)
{
cout << d.first << " " << d.second << endl;
}
ASSERT_EQ(fs.size(), 1);
system_error err;
ASSERT_EQ(fs::file_stat("dbfile", &err).type, scc::util::FileType::reg);
}
TEST_F(SqliteTest, exec_select)
{
Req req(db);
req.sql()
<< "create table t(a TEXT, b INT) STRICT;"
<< "insert into t values('hello!', 1);"
<< "insert into t values('goodbye', 2);"
<< "select * from t;";
int r = req.exec_select();
ASSERT_EQ(r, 2);
cout << "first col name: " << req.col_name(0) << endl;
ASSERT_EQ(req.col_name(0), "a");
string n;
req.col_name(1, n);
cout << "second col name: " << n << endl;
ASSERT_EQ(n, "b");
ASSERT_EQ(req.col_text(0), "hello!");
req.col_text(0, n);
ASSERT_EQ(n, "hello!");
ASSERT_EQ(req.col_int(1), 1);
ASSERT_EQ(req.next_row(), 2);
ASSERT_EQ(req.col_text(0), "goodbye");
req.col_text(0, n);
ASSERT_EQ(n, "goodbye");
ASSERT_EQ(req.col_int(1), 2);
ASSERT_EQ(req.next_row(), 0);
ASSERT_EQ(req.exec_select(), 0);
}
TEST_F(SqliteTest, exec)
{
reopen("file:dbfile?mode=rwc");
Req req(db);
int64_t big = 1;
big <<= 48;
cout << "big is " << big << endl;
req.sql()
<< "create table t(a VARCHAR PRIMARY KEY, b DOUBLE, c INTEGER DEFAULT 0);"
<< "insert into t (a, b) values('hello!', 1.1);"
<< "insert into t values('goodbye', 2.2, " << big << ");"
<< "select * from t;"
<< "insert into t (a, b) values('until we meet again', 3.3);";
req.exec();
req.clear();
req.sql() << "select b,c from t where a is 'goodbye';";
int r = req.exec_select();
ASSERT_EQ(r, 2);
ASSERT_EQ(req.col_real(0), 2.2);
ASSERT_EQ(req.col_int64(1), big);
}
TEST_F(SqliteTest, blob)
{
Req req(db);
req.sql()
<< "create table t(a BLOB) STRICT;"
<< "insert into t values(x'deadbeef');"
<< "select * from t;";
int r = req.exec_select();
ASSERT_EQ(r, 1);
vector<char> t = {'\xde', '\xad', '\xbe', '\xef'}, v;
req.col_blob(0, v);
ASSERT_EQ(t, v);
}
TEST_F(SqliteTest, two_conns_xact)
{
reopen("file:dbfile?mode=rwc");
Req r(db);
r.sql() << "create table t(a ANY) STRICT;";
r.exec();
Trans x(db);
ASSERT_FALSE(x.is_active());
x.begin();
ASSERT_TRUE(x.is_active());
r.clear();
r.sql() << "insert into t values(12345);";
r.exec();
Conn db2("file:dbfile?mode=ro");
Req r2(db2);
r2.sql() << "select * from t;";
ASSERT_EQ(r2.exec_select(), 0);
x.commit();
r2.reset();
ASSERT_EQ(r2.exec_select(), 1);
x.begin();
r.clear();
r.sql() << "insert into t values(45678);";
r.exec();
x.abort();
r.clear();
r.sql() << "select * from t where a is 45678;";
ASSERT_EQ(r.exec_select(), 0);
r2.clear();
r2.sql() << "insert into t values(45678);";
ASSERT_THROW(r2.exec(), runtime_error);
}