sqlite / tests /tests_alter_sqlite3ErrorIfNotEmpty.c
AryaWu's picture
Upload folder using huggingface_hub
7510827 verified
#include "sqliteInt.h"
#include "unity.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
/* Wrapper provided for static function under test */
extern void test_sqlite3ErrorIfNotEmpty(
Parse *pParse,
const char *zDb,
const char *zTab,
const char *zErr
);
static sqlite3 *gDb = NULL;
/* Helpers */
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;
}
}
/* Unity required hooks */
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;
}
}
/* Tests */
void test_sqlite3ErrorIfNotEmpty_empty_table_executes_without_error(void){
/* Setup schema: empty table */
exec_or_fail("CREATE TABLE t(a)");
/* Call target wrapper to build nested parse (ensures it handles normal names) */
Parse s = {0};
init_parse(&s);
const char *zErr = "table is not empty";
test_sqlite3ErrorIfNotEmpty(&s, "main", "t", zErr);
cleanup_parse(&s);
/* Validate functional intent by running the equivalent SQL directly */
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);
/* On empty table, this should succeed with SQLITE_OK and no error message */
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){
/* Setup schema: table with one row */
exec_or_fail("CREATE TABLE t2(a)");
exec_or_fail("INSERT INTO t2(a) VALUES(123)");
/* Call target wrapper */
Parse s = {0};
init_parse(&s);
const char *zErr = "cannot proceed: table has rows";
test_sqlite3ErrorIfNotEmpty(&s, "main", "t2", zErr);
cleanup_parse(&s);
/* Validate behavior by executing equivalent SQL directly */
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);
/* Expect an error. Historically, RAISE(ABORT, ...) maps to a constraint error.
So just assert that it is not SQLITE_OK and that the message contains our text. */
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){
/* Create a table name with quotes and a dot to verify proper identifier escaping */
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);
/* Call target wrapper using an error message with embedded quotes to exercise %Q */
Parse s = {0};
init_parse(&s);
const char *zErr = "msg with \"quotes\" and 'single quotes'";
test_sqlite3ErrorIfNotEmpty(&s, "main", zTab, zErr);
cleanup_parse(&s);
/* Empty table: executing the equivalent SQL should succeed */
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);
/* Now insert a row and confirm it fails with the message */
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){
/* Call target wrapper for a table that does not exist to ensure parse error captured */
Parse s = {0};
init_parse(&s);
test_sqlite3ErrorIfNotEmpty(&s, "main", "no_such_table_xyz", "any error");
/* We expect an error recorded by the nested parse */
TEST_ASSERT_TRUE(s.nErr > 0);
TEST_ASSERT_NOT_NULL(s.zErrMsg);
/* Avoid asserting exact text; just ensure an error was captured */
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();
}