|
|
#include "sqliteInt.h" |
|
|
#include "unity.h" |
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
|
|
|
|
|
|
extern void test_errorMPrintf(sqlite3_context *pCtx, const char *zFmt, ...); |
|
|
|
|
|
|
|
|
void setUp(void) { |
|
|
|
|
|
} |
|
|
void tearDown(void) { |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void xErr_basic(sqlite3_context *ctx, int argc, sqlite3_value **argv){ |
|
|
|
|
|
const char *name = (const char*)sqlite3_value_text(argv[0]); |
|
|
int a = sqlite3_value_int(argv[1]); |
|
|
sqlite3_int64 b = sqlite3_value_int64(argv[2]); |
|
|
double c = sqlite3_value_double(argv[3]); |
|
|
test_errorMPrintf(ctx, "Name:%s Int:%d I64:%lld Dbl:%.2f", name, a, b, c); |
|
|
} |
|
|
|
|
|
static void xErr_percent(sqlite3_context *ctx, int argc, sqlite3_value **argv){ |
|
|
|
|
|
(void)argc; (void)argv; |
|
|
test_errorMPrintf(ctx, "Rate: %d%%", 100); |
|
|
} |
|
|
|
|
|
static void xErr_null(sqlite3_context *ctx, int argc, sqlite3_value **argv){ |
|
|
|
|
|
const char *s = (const char*)sqlite3_value_text(argv[0]); |
|
|
test_errorMPrintf(ctx, "S=%s", s); |
|
|
} |
|
|
|
|
|
static void xErr_long(sqlite3_context *ctx, int argc, sqlite3_value **argv){ |
|
|
|
|
|
const char *s = (const char*)sqlite3_value_text(argv[0]); |
|
|
test_errorMPrintf(ctx, "Long:%s", s); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char* step_and_capture_errmsg(sqlite3 *db, sqlite3_stmt *stmt, int *pRc){ |
|
|
int rc = sqlite3_step(stmt); |
|
|
if( pRc ) *pRc = rc; |
|
|
if( rc==SQLITE_ERROR ){ |
|
|
const char *z = sqlite3_errmsg(db); |
|
|
size_t n = strlen(z); |
|
|
char *copy = (char*)sqlite3_malloc((int)n+1); |
|
|
if( copy ){ |
|
|
memcpy(copy, z, n+1); |
|
|
} |
|
|
return copy; |
|
|
} |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
|
|
|
void test_errorMPrintf_formats_basic(void){ |
|
|
sqlite3 *db = 0; |
|
|
sqlite3_stmt *stmt = 0; |
|
|
int rc; |
|
|
|
|
|
rc = sqlite3_open(":memory:", &db); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
|
|
|
rc = sqlite3_create_function_v2(db, "t_basic", 4, SQLITE_UTF8, NULL, |
|
|
xErr_basic, NULL, NULL, NULL); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
|
|
|
const char *sql = "SELECT t_basic('Alice', 42, 1234567890123, 3.14159)"; |
|
|
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
|
|
|
int stepRc = SQLITE_OK; |
|
|
char *errmsg = step_and_capture_errmsg(db, stmt, &stepRc); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, stepRc); |
|
|
|
|
|
|
|
|
const char *expected = "Name:Alice Int:42 I64:1234567890123 Dbl:3.14"; |
|
|
TEST_ASSERT_NOT_NULL(errmsg); |
|
|
TEST_ASSERT_EQUAL_STRING(expected, errmsg); |
|
|
|
|
|
sqlite3_free(errmsg); |
|
|
sqlite3_finalize(stmt); |
|
|
sqlite3_close(db); |
|
|
} |
|
|
|
|
|
|
|
|
void test_errorMPrintf_handles_percent_literal(void){ |
|
|
sqlite3 *db = 0; |
|
|
sqlite3_stmt *stmt = 0; |
|
|
int rc; |
|
|
|
|
|
rc = sqlite3_open(":memory:", &db); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
|
|
|
rc = sqlite3_create_function_v2(db, "t_pct", 0, SQLITE_UTF8, NULL, |
|
|
xErr_percent, NULL, NULL, NULL); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
|
|
|
const char *sql = "SELECT t_pct()"; |
|
|
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
|
|
|
int stepRc = SQLITE_OK; |
|
|
char *errmsg = step_and_capture_errmsg(db, stmt, &stepRc); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, stepRc); |
|
|
|
|
|
const char *expected = "Rate: 100%"; |
|
|
TEST_ASSERT_NOT_NULL(errmsg); |
|
|
TEST_ASSERT_EQUAL_STRING(expected, errmsg); |
|
|
|
|
|
sqlite3_free(errmsg); |
|
|
sqlite3_finalize(stmt); |
|
|
sqlite3_close(db); |
|
|
} |
|
|
|
|
|
|
|
|
void test_errorMPrintf_null_string_becomes_NULL_literal(void){ |
|
|
sqlite3 *db = 0; |
|
|
sqlite3_stmt *stmt = 0; |
|
|
int rc; |
|
|
|
|
|
rc = sqlite3_open(":memory:", &db); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
|
|
|
rc = sqlite3_create_function_v2(db, "t_null", 1, SQLITE_UTF8, NULL, |
|
|
xErr_null, NULL, NULL, NULL); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
|
|
|
const char *sql = "SELECT t_null(NULL)"; |
|
|
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
|
|
|
int stepRc = SQLITE_OK; |
|
|
char *errmsg = step_and_capture_errmsg(db, stmt, &stepRc); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, stepRc); |
|
|
|
|
|
const char *expected = "S=(NULL)"; |
|
|
TEST_ASSERT_NOT_NULL(errmsg); |
|
|
TEST_ASSERT_EQUAL_STRING(expected, errmsg); |
|
|
|
|
|
sqlite3_free(errmsg); |
|
|
sqlite3_finalize(stmt); |
|
|
sqlite3_close(db); |
|
|
} |
|
|
|
|
|
|
|
|
void test_errorMPrintf_long_message(void){ |
|
|
sqlite3 *db = 0; |
|
|
sqlite3_stmt *stmt = 0; |
|
|
int rc; |
|
|
|
|
|
|
|
|
const int N = 50000; |
|
|
char *longInput = (char*)malloc((size_t)N + 1); |
|
|
TEST_ASSERT_NOT_NULL(longInput); |
|
|
memset(longInput, 'A', (size_t)N); |
|
|
longInput[N] = '\0'; |
|
|
|
|
|
|
|
|
size_t prefixLen = 5; |
|
|
char *expected = (char*)malloc(prefixLen + (size_t)N + 1); |
|
|
TEST_ASSERT_NOT_NULL(expected); |
|
|
memcpy(expected, "Long:", prefixLen); |
|
|
memcpy(expected + prefixLen, longInput, (size_t)N + 1); |
|
|
|
|
|
rc = sqlite3_open(":memory:", &db); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
|
|
|
rc = sqlite3_create_function_v2(db, "t_long", 1, SQLITE_UTF8, NULL, |
|
|
xErr_long, NULL, NULL, NULL); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
|
|
|
rc = sqlite3_prepare_v2(db, "SELECT t_long(?)", -1, &stmt, NULL); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
|
|
|
rc = sqlite3_bind_text(stmt, 1, longInput, -1, SQLITE_TRANSIENT); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
|
|
|
int stepRc = SQLITE_OK; |
|
|
char *errmsg = step_and_capture_errmsg(db, stmt, &stepRc); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, stepRc); |
|
|
|
|
|
TEST_ASSERT_NOT_NULL(errmsg); |
|
|
TEST_ASSERT_EQUAL_STRING(expected, errmsg); |
|
|
|
|
|
sqlite3_free(errmsg); |
|
|
sqlite3_finalize(stmt); |
|
|
sqlite3_close(db); |
|
|
|
|
|
free(expected); |
|
|
free(longInput); |
|
|
} |
|
|
|
|
|
int main(void) { |
|
|
UNITY_BEGIN(); |
|
|
RUN_TEST(test_errorMPrintf_formats_basic); |
|
|
RUN_TEST(test_errorMPrintf_handles_percent_literal); |
|
|
RUN_TEST(test_errorMPrintf_null_string_becomes_NULL_literal); |
|
|
RUN_TEST(test_errorMPrintf_long_message); |
|
|
return UNITY_END(); |
|
|
} |