| #include "sqliteInt.h" |
| #include "unity.h" |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
|
|
| |
| extern void test_addConstraintFunc(sqlite3_context*, int, sqlite3_value**); |
|
|
| static sqlite3 *gDb = NULL; |
| static const char *gFuncName = "test_addc"; |
|
|
| |
| 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"); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| 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; |
| } |
| } |
|
|
| |
| 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); |
| } |
|
|
| |
| 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); |
| } |
|
|
| |
| 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); |
| } |
|
|
| |
| |
| |
| 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); |
| } |
|
|
| |
| 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); |
| } |
|
|
| |
| 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); |
| } |
|
|
| |
| void test_addConstraintFunc_out_of_range_column_reports_corrupt(void){ |
| int stepRc = 0, err = 0; |
| |
| 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); |
| } |
|
|
| |
| void test_addConstraintFunc_malformed_sql_reports_corrupt(void){ |
| int stepRc = 0, err = 0; |
| |
| 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(); |
| } |