如何创建 sqlite3_value 以使用 gtest 进行测试
How to create a sqlite3_value for testing with gtest
我正在为 sqlite3 写一个包装器 class 只是 4 乐趣和学习 c++11 和 gtest。我正在用 gtest 测试我的包装器。在一个特定的测试用例中,我需要一个 sqlite3_value 对象来比较我的函数结果。我不知道如何从头开始创建 sqlite3_value 对象。我在网上搜索并找到了这个解决方案:
sqlite3 *tmpDB;
sqlite3_open_v2(":memory", &tmpDB, SQLITE_OPEN_READWRITE, 0);
sqlite3_stmt *tmpStmt = nullptr;
sqlite3_prepare_v2(tmpDB, "SELECT ?;", 9, &tmpStmt, nullptr);
sqlite3_bind_text(tmpStmt, 0, "paul", 4, SQLITE_TRANSIENT);
int res = sqlite3_step(tmpStmt);
std::string s(reinterpret_cast<const char*>(sqlite3_value_text(sqlite3_column_value(tmpStmt, 0)))); /*Here throws the exception below*/
sqlite3_finalize(tmpStmt);
调用 sqlite3_finalize() 之前的字符串构造将抛出以下异常:
C++ exception with description "basic_string::_M_construct null not valid" thrown in the test body
.
我尝试了堆栈溢出的解决方案:
Stack Overflow std::basic_string solution
但我有同样的例外。
我不确定是否可以从头开始构建 sqlite3_value。我尝试 "build" sqlite3_value 的方法是正确的吗?
也许我必须考虑使用其他类型作为 std::string。我读到一些原因,例如 std::string 不支持文本 不是纯 ACSII。是吗?
有什么建议吗?
in-memory 数据库的名称不是 :memory
,而是 :memory:
。
sqlite3_bind_text()的最后一个参数不能为NULL。
但是你的问题是查询永远不会执行。
此外,如图sqlite3_column_value() documentation:
the pointers returned are valid until … sqlite3_step() or sqlite3_reset() or sqlite3_finalize() is called.
您必须在完成声明之前提取文本。
或者,将语句对象保留在 DataObject
.
中
此外,您必须检查所有函数的 return 值是否有错误。
首先要做的事情:您引用的异常意味着您将 nullptr
传递给了 std::string
构造函数。这是被禁止的。您传递空指针的原因是您在不代表 STRING 值的值上使用 sqlite3_value_text
。这又是查询失败造成的
CL目前对答案的修改有很多好的方面。让我们从最重要的建议开始:
Also, you must check the return values of all functions for errors.
你说你正在使用 Google 测试,所以让我们使用 EXPECT_EQ 语句来找出函数是否确实 return 你期望的值。这是一个完整的最小示例,添加了错误检查:
#include <sqlite3.h>
#include <string>
#include <gtest/gtest.h>
int main(void)
{
sqlite3 *tmpDB;
EXPECT_EQ(SQLITE_OK, sqlite3_open_v2(":memory", &tmpDB, SQLITE_OPEN_READWRITE, 0));
sqlite3_stmt *tmpStmt = nullptr;
EXPECT_EQ(SQLITE_OK, sqlite3_prepare_v2(tmpDB, "SELECT ?;", 9, &tmpStmt, nullptr));
EXPECT_EQ(SQLITE_OK, sqlite3_bind_text(tmpStmt, 0, "paul", 4, SQLITE_TRANSIENT));
int res = sqlite3_step(tmpStmt);
EXPECT_EQ(SQLITE_ROW, res);
std::string s(reinterpret_cast<const char*>(sqlite3_value_text(sqlite3_column_value(tmpStmt, 0))));
EXPECT_EQ(SQLITE_OK, sqlite3_finalize(tmpStmt));
}
这样会输出很多期望失败。哎呀!第一个期望失败是 sqlite_open returning 14 (SQLITE_CANTOPEN)。仔细看CL给出的答案就可以找到原因了,其实仔细看第一句应该就够了。
修复该问题后,sqlite3_bind_text 上的 EXPECT_EQ 失败,错误代码为 25 (SQLITE_RANGE)。阅读 sqlite3_bind_text 的文档,特别是描述第二个参数的段落的前两句,以找出此调用中的错误。
也解决了这个问题,我不再遇到异常或任何预期失败。
我正在为 sqlite3 写一个包装器 class 只是 4 乐趣和学习 c++11 和 gtest。我正在用 gtest 测试我的包装器。在一个特定的测试用例中,我需要一个 sqlite3_value 对象来比较我的函数结果。我不知道如何从头开始创建 sqlite3_value 对象。我在网上搜索并找到了这个解决方案:
sqlite3 *tmpDB;
sqlite3_open_v2(":memory", &tmpDB, SQLITE_OPEN_READWRITE, 0);
sqlite3_stmt *tmpStmt = nullptr;
sqlite3_prepare_v2(tmpDB, "SELECT ?;", 9, &tmpStmt, nullptr);
sqlite3_bind_text(tmpStmt, 0, "paul", 4, SQLITE_TRANSIENT);
int res = sqlite3_step(tmpStmt);
std::string s(reinterpret_cast<const char*>(sqlite3_value_text(sqlite3_column_value(tmpStmt, 0)))); /*Here throws the exception below*/
sqlite3_finalize(tmpStmt);
调用 sqlite3_finalize() 之前的字符串构造将抛出以下异常:
C++ exception with description "basic_string::_M_construct null not valid" thrown in the test body
.
我尝试了堆栈溢出的解决方案: Stack Overflow std::basic_string solution 但我有同样的例外。
我不确定是否可以从头开始构建 sqlite3_value。我尝试 "build" sqlite3_value 的方法是正确的吗?
也许我必须考虑使用其他类型作为 std::string。我读到一些原因,例如 std::string 不支持文本 不是纯 ACSII。是吗?
有什么建议吗?
in-memory 数据库的名称不是 :memory
,而是 :memory:
。
sqlite3_bind_text()的最后一个参数不能为NULL。
但是你的问题是查询永远不会执行。
此外,如图sqlite3_column_value() documentation:
the pointers returned are valid until … sqlite3_step() or sqlite3_reset() or sqlite3_finalize() is called.
您必须在完成声明之前提取文本。
或者,将语句对象保留在 DataObject
.
此外,您必须检查所有函数的 return 值是否有错误。
首先要做的事情:您引用的异常意味着您将 nullptr
传递给了 std::string
构造函数。这是被禁止的。您传递空指针的原因是您在不代表 STRING 值的值上使用 sqlite3_value_text
。这又是查询失败造成的
CL目前对答案的修改有很多好的方面。让我们从最重要的建议开始:
Also, you must check the return values of all functions for errors.
你说你正在使用 Google 测试,所以让我们使用 EXPECT_EQ 语句来找出函数是否确实 return 你期望的值。这是一个完整的最小示例,添加了错误检查:
#include <sqlite3.h>
#include <string>
#include <gtest/gtest.h>
int main(void)
{
sqlite3 *tmpDB;
EXPECT_EQ(SQLITE_OK, sqlite3_open_v2(":memory", &tmpDB, SQLITE_OPEN_READWRITE, 0));
sqlite3_stmt *tmpStmt = nullptr;
EXPECT_EQ(SQLITE_OK, sqlite3_prepare_v2(tmpDB, "SELECT ?;", 9, &tmpStmt, nullptr));
EXPECT_EQ(SQLITE_OK, sqlite3_bind_text(tmpStmt, 0, "paul", 4, SQLITE_TRANSIENT));
int res = sqlite3_step(tmpStmt);
EXPECT_EQ(SQLITE_ROW, res);
std::string s(reinterpret_cast<const char*>(sqlite3_value_text(sqlite3_column_value(tmpStmt, 0))));
EXPECT_EQ(SQLITE_OK, sqlite3_finalize(tmpStmt));
}
这样会输出很多期望失败。哎呀!第一个期望失败是 sqlite_open returning 14 (SQLITE_CANTOPEN)。仔细看CL给出的答案就可以找到原因了,其实仔细看第一句应该就够了。
修复该问题后,sqlite3_bind_text 上的 EXPECT_EQ 失败,错误代码为 25 (SQLITE_RANGE)。阅读 sqlite3_bind_text 的文档,特别是描述第二个参数的段落的前两句,以找出此调用中的错误。
也解决了这个问题,我不再遇到异常或任何预期失败。