|
|
#include "sqliteInt.h" |
|
|
#include "unity.h" |
|
|
#include <string.h> |
|
|
#include <stdlib.h> |
|
|
#include <stdio.h> |
|
|
|
|
|
|
|
|
extern void test_sqlite3ErrorIfNotEmpty( |
|
|
Parse *pParse, |
|
|
const char *zDb, |
|
|
const char *zTab, |
|
|
const char *zErr |
|
|
); |
|
|
|
|
|
static sqlite3 *gDb = NULL; |
|
|
|
|
|
|
|
|
static void exec_or_fail(const char *zSql){ |
|
|
char *zErr = NULL; |
|
|
int rc = sqlite3_exec(gDb, zSql, 0, 0, &zErr); |
|
|
if( rc!=SQLITE_OK ){ |
|
|
fprintf(stderr, "SQL failed: %s\n rc=%d err=%s\n", zSql, rc, zErr?zErr:"(null)"); |
|
|
} |
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "exec_or_fail SQL error"); |
|
|
if( zErr ) sqlite3_free(zErr); |
|
|
} |
|
|
|
|
|
static void init_parse(Parse *p){ |
|
|
memset(p, 0, sizeof(*p)); |
|
|
p->db = gDb; |
|
|
} |
|
|
|
|
|
static void cleanup_parse(Parse *p){ |
|
|
if( p->pVdbe ){ |
|
|
sqlite3VdbeDelete(p->pVdbe); |
|
|
p->pVdbe = NULL; |
|
|
} |
|
|
if( p->zErrMsg ){ |
|
|
sqlite3_free(p->zErrMsg); |
|
|
p->zErrMsg = NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void setUp(void) { |
|
|
int rc = sqlite3_open(":memory:", &gDb); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
} |
|
|
|
|
|
void tearDown(void) { |
|
|
if( gDb ){ |
|
|
int rc = sqlite3_close(gDb); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
gDb = NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void test_sqlite3ErrorIfNotEmpty_empty_table_executes_without_error(void){ |
|
|
|
|
|
exec_or_fail("CREATE TABLE t(a)"); |
|
|
|
|
|
|
|
|
Parse s = {0}; |
|
|
init_parse(&s); |
|
|
const char *zErr = "table is not empty"; |
|
|
test_sqlite3ErrorIfNotEmpty(&s, "main", "t", zErr); |
|
|
cleanup_parse(&s); |
|
|
|
|
|
|
|
|
char *zSql = sqlite3_mprintf("SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"", |
|
|
zErr, "main", "t"); |
|
|
TEST_ASSERT_NOT_NULL(zSql); |
|
|
|
|
|
char *zExecErr = NULL; |
|
|
int rc = sqlite3_exec(gDb, zSql, 0, 0, &zExecErr); |
|
|
|
|
|
if( rc!=SQLITE_OK && zExecErr ){ |
|
|
fprintf(stderr, "Unexpected error on empty table: %s\n", zExecErr); |
|
|
} |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
TEST_ASSERT_NULL(zExecErr); |
|
|
|
|
|
sqlite3_free(zSql); |
|
|
} |
|
|
|
|
|
void test_sqlite3ErrorIfNotEmpty_nonempty_table_raises_error_with_message(void){ |
|
|
|
|
|
exec_or_fail("CREATE TABLE t2(a)"); |
|
|
exec_or_fail("INSERT INTO t2(a) VALUES(123)"); |
|
|
|
|
|
|
|
|
Parse s = {0}; |
|
|
init_parse(&s); |
|
|
const char *zErr = "cannot proceed: table has rows"; |
|
|
test_sqlite3ErrorIfNotEmpty(&s, "main", "t2", zErr); |
|
|
cleanup_parse(&s); |
|
|
|
|
|
|
|
|
char *zSql = sqlite3_mprintf("SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"", |
|
|
zErr, "main", "t2"); |
|
|
TEST_ASSERT_NOT_NULL(zSql); |
|
|
|
|
|
char *zExecErr = NULL; |
|
|
int rc = sqlite3_exec(gDb, zSql, 0, 0, &zExecErr); |
|
|
|
|
|
|
|
|
TEST_ASSERT_NOT_EQUAL(INT, SQLITE_OK, rc); |
|
|
TEST_ASSERT_NOT_NULL(zExecErr); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(strstr(zExecErr, zErr), "Error message should contain the provided zErr text"); |
|
|
|
|
|
sqlite3_free(zExecErr); |
|
|
sqlite3_free(zSql); |
|
|
} |
|
|
|
|
|
void test_sqlite3ErrorIfNotEmpty_identifier_quoting_with_special_table_name(void){ |
|
|
|
|
|
const char *zTab = "weird\"name.dot"; |
|
|
char *zCreate = sqlite3_mprintf("CREATE TABLE \"%w\"(a)", zTab); |
|
|
TEST_ASSERT_NOT_NULL(zCreate); |
|
|
exec_or_fail(zCreate); |
|
|
sqlite3_free(zCreate); |
|
|
|
|
|
|
|
|
Parse s = {0}; |
|
|
init_parse(&s); |
|
|
const char *zErr = "msg with \"quotes\" and 'single quotes'"; |
|
|
test_sqlite3ErrorIfNotEmpty(&s, "main", zTab, zErr); |
|
|
cleanup_parse(&s); |
|
|
|
|
|
|
|
|
char *zSql = sqlite3_mprintf("SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"", |
|
|
zErr, "main", zTab); |
|
|
TEST_ASSERT_NOT_NULL(zSql); |
|
|
|
|
|
char *zExecErr = NULL; |
|
|
int rc = sqlite3_exec(gDb, zSql, 0, 0, &zExecErr); |
|
|
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc); |
|
|
TEST_ASSERT_NULL(zExecErr); |
|
|
|
|
|
sqlite3_free(zSql); |
|
|
|
|
|
|
|
|
char *zInsert = sqlite3_mprintf("INSERT INTO \"%w\"(a) VALUES(1)", zTab); |
|
|
TEST_ASSERT_NOT_NULL(zInsert); |
|
|
exec_or_fail(zInsert); |
|
|
sqlite3_free(zInsert); |
|
|
|
|
|
zSql = sqlite3_mprintf("SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"", |
|
|
zErr, "main", zTab); |
|
|
TEST_ASSERT_NOT_NULL(zSql); |
|
|
rc = sqlite3_exec(gDb, zSql, 0, 0, &zExecErr); |
|
|
TEST_ASSERT_NOT_EQUAL(INT, SQLITE_OK, rc); |
|
|
TEST_ASSERT_NOT_NULL(zExecErr); |
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(strstr(zExecErr, zErr), "Error message should contain zErr"); |
|
|
sqlite3_free(zExecErr); |
|
|
sqlite3_free(zSql); |
|
|
} |
|
|
|
|
|
void test_sqlite3ErrorIfNotEmpty_nonexistent_table_sets_parse_error(void){ |
|
|
|
|
|
Parse s = {0}; |
|
|
init_parse(&s); |
|
|
test_sqlite3ErrorIfNotEmpty(&s, "main", "no_such_table_xyz", "any error"); |
|
|
|
|
|
TEST_ASSERT_TRUE(s.nErr > 0); |
|
|
TEST_ASSERT_NOT_NULL(s.zErrMsg); |
|
|
|
|
|
cleanup_parse(&s); |
|
|
} |
|
|
|
|
|
int main(void) { |
|
|
UNITY_BEGIN(); |
|
|
|
|
|
RUN_TEST(test_sqlite3ErrorIfNotEmpty_empty_table_executes_without_error); |
|
|
RUN_TEST(test_sqlite3ErrorIfNotEmpty_nonempty_table_raises_error_with_message); |
|
|
RUN_TEST(test_sqlite3ErrorIfNotEmpty_identifier_quoting_with_special_table_name); |
|
|
RUN_TEST(test_sqlite3ErrorIfNotEmpty_nonexistent_table_sets_parse_error); |
|
|
|
|
|
return UNITY_END(); |
|
|
} |