sqlite / tests /tests_alter_addConstraintFunc.c
AryaWu's picture
Upload folder using huggingface_hub
7510827 verified
#include "sqliteInt.h"
#include "unity.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* The wrapper for the static function is provided by the module under test. */
extern void test_addConstraintFunc(sqlite3_context*, int, sqlite3_value**);
static sqlite3 *gDb = NULL;
static const char *gFuncName = "test_addc";
/* Helper to register the function under a SQL name on gDb */
static void register_add_constraint_func(void){
int rc = sqlite3_create_function(gDb, gFuncName, 3, SQLITE_UTF8, 0,
test_addConstraintFunc, 0, 0);
TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_create_function failed");
}
/* Helper to call the function and capture result text or error.
Returns a heap-allocated copy of the result text (sqlite3_mprintf) on success
(caller must sqlite3_free), or NULL if result is SQL NULL or on error.
If out_step_rc is non-NULL, it is set to the return from sqlite3_step.
If out_errcode is non-NULL, it is set to sqlite3_errcode(gDb) after step.
*/
static char* call_add_constraint(const char *zCreate, const char *zCons, int iCol,
int *out_step_rc, int *out_errcode){
char *zSql = sqlite3_mprintf("SELECT %s(%Q,%Q,%d)", gFuncName, zCreate, zCons, iCol);
TEST_ASSERT_NOT_NULL_MESSAGE(zSql, "sqlite3_mprintf returned NULL");
sqlite3_stmt *pStmt = NULL;
int rc = sqlite3_prepare_v2(gDb, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_prepare_v2 failed");
rc = sqlite3_step(pStmt);
if( out_step_rc ) *out_step_rc = rc;
if( out_errcode ) *out_errcode = sqlite3_errcode(gDb);
char *res = NULL;
if( rc==SQLITE_ROW ){
const unsigned char *txt = sqlite3_column_text(pStmt, 0);
if( txt ){
res = (char*)sqlite3_mprintf("%s", txt);
}
}
sqlite3_finalize(pStmt);
return res;
}
void setUp(void) {
int rc = sqlite3_open(":memory:", &gDb);
TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");
register_add_constraint_func();
}
void tearDown(void) {
if( gDb ){
sqlite3_close(gDb);
gDb = NULL;
}
}
/* Test: insert constraint into the first (0th) column */
void test_addConstraintFunc_adds_to_first_column_simple(void){
int stepRc = 0, err = 0;
const char *inSql = "CREATE TABLE t(a, b)";
const char *cons = "CHECK(a>0)";
char *out = call_add_constraint(inSql, cons, 0, &stepRc, &err);
TEST_ASSERT_EQUAL_INT(SQLITE_ROW, stepRc);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, err);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_STRING("CREATE TABLE t(a CHECK(a>0), b)", out);
sqlite3_free(out);
}
/* Test: insert constraint into the second (1st) column */
void test_addConstraintFunc_adds_to_second_column_simple(void){
int stepRc = 0, err = 0;
const char *inSql = "CREATE TABLE t(a, b)";
const char *cons = "DEFAULT 5";
char *out = call_add_constraint(inSql, cons, 1, &stepRc, &err);
TEST_ASSERT_EQUAL_INT(SQLITE_ROW, stepRc);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, err);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_STRING("CREATE TABLE t(a, b DEFAULT 5)", out);
sqlite3_free(out);
}
/* Test: append a table constraint with iCol < 0 (use -1) */
void test_addConstraintFunc_appends_table_constraint_neg1(void){
int stepRc = 0, err = 0;
const char *inSql = "CREATE TABLE t(a INTEGER, b TEXT)";
const char *cons = "UNIQUE(a,b)";
char *out = call_add_constraint(inSql, cons, -1, &stepRc, &err);
TEST_ASSERT_EQUAL_INT(SQLITE_ROW, stepRc);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, err);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_STRING("CREATE TABLE t(a INTEGER, b TEXT, UNIQUE(a,b))", out);
sqlite3_free(out);
}
/* Test: handles comments and nested parentheses in type, inserts before delimiter.
Note: The implementation advances past whitespace/comments before the delimiter,
so the inserted constraint appears AFTER any trailing comments and BEFORE the comma. */
void test_addConstraintFunc_handles_comments_and_parens(void){
int stepRc = 0, err = 0;
const char *inSql =
"CREATE TABLE t( /*c*/ a DECIMAL(10, 5) /*x*/, b TEXT )";
const char *cons = "NOT NULL";
char *out = call_add_constraint(inSql, cons, 0, &stepRc, &err);
TEST_ASSERT_EQUAL_INT(SQLITE_ROW, stepRc);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, err);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_STRING(
"CREATE TABLE t( /*c*/ a DECIMAL(10, 5) /*x*/ NOT NULL, b TEXT )", out);
sqlite3_free(out);
}
/* Test: nested parentheses inside default expressions */
void test_addConstraintFunc_handles_nested_parens_in_defaults(void){
int stepRc = 0, err = 0;
const char *inSql =
"CREATE TABLE t(a TEXT DEFAULT (printf('x(%d)', 1)), b INT)";
const char *cons = "CHECK(length(a)>0)";
char *out = call_add_constraint(inSql, cons, 0, &stepRc, &err);
TEST_ASSERT_EQUAL_INT(SQLITE_ROW, stepRc);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, err);
TEST_ASSERT_NOT_NULL(out);
TEST_ASSERT_EQUAL_STRING(
"CREATE TABLE t(a TEXT DEFAULT (printf('x(%d)', 1)) CHECK(length(a)>0), b INT)", out);
sqlite3_free(out);
}
/* Test: NULL SQL input returns NULL result (no error set) */
void test_addConstraintFunc_null_sql_returns_null(void){
int stepRc = 0, err = 0;
char *out = call_add_constraint(NULL, "ANY", 0, &stepRc, &err);
TEST_ASSERT_EQUAL_INT(SQLITE_ROW, stepRc);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, err);
TEST_ASSERT_NULL(out);
sqlite3_free(out); /* ok to free NULL */
}
/* Test: out-of-range column index triggers SQLITE_CORRUPT via illegal token handling */
void test_addConstraintFunc_out_of_range_column_reports_corrupt(void){
int stepRc = 0, err = 0;
/* Only 1 column present, ask for column index 5 */
const char *inSql = "CREATE TABLE t(a)";
char *out = call_add_constraint(inSql, "ZZZ", 5, &stepRc, &err);
TEST_ASSERT(out == NULL);
TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, stepRc);
TEST_ASSERT_EQUAL_INT(SQLITE_CORRUPT, err);
}
/* Test: malformed SQL (unterminated string) triggers SQLITE_CORRUPT */
void test_addConstraintFunc_malformed_sql_reports_corrupt(void){
int stepRc = 0, err = 0;
/* Unterminated string literal inside column definition */
const char *inSql = "CREATE TABLE t(a DEFAULT 'unterminated, b INT)";
char *out = call_add_constraint(inSql, "NOT NULL", 0, &stepRc, &err);
TEST_ASSERT(out == NULL);
TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, stepRc);
TEST_ASSERT_EQUAL_INT(SQLITE_CORRUPT, err);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_addConstraintFunc_adds_to_first_column_simple);
RUN_TEST(test_addConstraintFunc_adds_to_second_column_simple);
RUN_TEST(test_addConstraintFunc_appends_table_constraint_neg1);
RUN_TEST(test_addConstraintFunc_handles_comments_and_parens);
RUN_TEST(test_addConstraintFunc_handles_nested_parens_in_defaults);
RUN_TEST(test_addConstraintFunc_null_sql_returns_null);
RUN_TEST(test_addConstraintFunc_out_of_range_column_reports_corrupt);
RUN_TEST(test_addConstraintFunc_malformed_sql_reports_corrupt);
return UNITY_END();
}