#include "sqliteInt.h" #include "unity.h" #include #include /* Wrapper provided by build system for static function under test */ extern void test_findConstraintFunc(sqlite3_context *ctx, int NotUsed, sqlite3_value **argv); /* UDF that forwards to the function under test so we can get a valid sqlite3_context */ static void udf_findc(sqlite3_context *ctx, int argc, sqlite3_value **argv){ /* Forward directly to the function under test. The function only uses the first two args. */ (void)argc; /* Silence unused warning since function ignores argc */ test_findConstraintFunc(ctx, 0, argv); } static void register_findc(sqlite3 *db){ int rc = sqlite3_create_function(db, "findc", 2, SQLITE_UTF8, 0, udf_findc, 0, 0); TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_create_function(findc) failed"); } static void assert_findc_result(sqlite3 *db, const char *sqlDef, /* CREATE TABLE SQL or other */ const char *consName, /* constraint name, may be NULL */ int expectType, /* SQLITE_INTEGER or SQLITE_NULL */ int expectInt){ /* expected int if expectType==SQLITE_INTEGER */ sqlite3_stmt *stmt = 0; int rc = sqlite3_prepare_v2(db, "SELECT findc(?,?)", -1, &stmt, 0); TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "prepare SELECT findc failed"); if( sqlDef ){ rc = sqlite3_bind_text(stmt, 1, sqlDef, -1, SQLITE_TRANSIENT); }else{ rc = sqlite3_bind_null(stmt, 1); } TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "bind #1 failed"); if( consName ){ rc = sqlite3_bind_text(stmt, 2, consName, -1, SQLITE_TRANSIENT); }else{ rc = sqlite3_bind_null(stmt, 2); } TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "bind #2 failed"); rc = sqlite3_step(stmt); TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_ROW, rc, "step did not return row"); int gotType = sqlite3_column_type(stmt, 0); TEST_ASSERT_EQUAL_INT(expectType, gotType); if( expectType==SQLITE_INTEGER ){ int got = sqlite3_column_int(stmt, 0); TEST_ASSERT_EQUAL_INT(expectInt, got); } rc = sqlite3_step(stmt); TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_DONE, rc, "expected single row"); rc = sqlite3_finalize(stmt); TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "finalize failed"); } /* Unity hooks */ void setUp(void) { /* No-op */ } void tearDown(void) { /* No-op */ } /* Tests */ static void test_findConstraintFunc_basic_match(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); register_findc(db); const char *sql = "CREATE TABLE t (" " a INT," " CONSTRAINT c1 CHECK(a > 0)," " b TEXT" ");"; /* Exact name */ assert_findc_result(db, sql, "c1", SQLITE_INTEGER, 1); /* Not present */ assert_findc_result(db, sql, "c2", SQLITE_INTEGER, 0); sqlite3_close(db); } static void test_findConstraintFunc_case_insensitive_and_quoted(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); register_findc(db); /* Quoted identifier with spaces; test case-insensitive compare */ const char *sql = "CREATE TABLE t (" " a INT," " CONSTRAINT \"My Constr\" UNIQUE(a)" ");"; assert_findc_result(db, sql, "My Constr", SQLITE_INTEGER, 1); assert_findc_result(db, sql, "my constr", SQLITE_INTEGER, 1); assert_findc_result(db, sql, "MY CONSTR", SQLITE_INTEGER, 1); assert_findc_result(db, sql, "Other", SQLITE_INTEGER, 0); sqlite3_close(db); } static void test_findConstraintFunc_bracket_and_backtick_quoted(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); register_findc(db); const char *sql1 = "CREATE TABLE t1 (" " a INT," " CONSTRAINT [C-Name] CHECK(a IS NOT NULL)" ");"; assert_findc_result(db, sql1, "c-name", SQLITE_INTEGER, 1); assert_findc_result(db, sql1, "C-Name", SQLITE_INTEGER, 1); assert_findc_result(db, sql1, "other", SQLITE_INTEGER, 0); const char *sql2 = "CREATE TABLE t2 (" " a INT," " CONSTRAINT `bk` CHECK(a > 0)" ");"; assert_findc_result(db, sql2, "bk", SQLITE_INTEGER, 1); assert_findc_result(db, sql2, "BK", SQLITE_INTEGER, 1); assert_findc_result(db, sql2, "xx", SQLITE_INTEGER, 0); sqlite3_close(db); } static void test_findConstraintFunc_with_comments_and_nested_parens(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); register_findc(db); const char *sql = "/* heading comment */ CREATE /* mid */ TABLE t (\n" " a INT, -- column a\n" " CONSTRAINT /*name*/ \"C 1\" CHECK( (a > 0) AND (a < 10) )\n" "); -- trailer\n"; assert_findc_result(db, sql, "C 1", SQLITE_INTEGER, 1); assert_findc_result(db, sql, "c 1", SQLITE_INTEGER, 1); assert_findc_result(db, sql, "not-there", SQLITE_INTEGER, 0); sqlite3_close(db); } static void test_findConstraintFunc_no_named_constraints_returns_0(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); register_findc(db); /* Constraints without explicit "CONSTRAINT " should not match any name */ const char *sql = "CREATE TABLE t (" " a INT," " UNIQUE(a)," " PRIMARY KEY(a)" ");"; assert_findc_result(db, sql, "anything", SQLITE_INTEGER, 0); sqlite3_close(db); } static void test_findConstraintFunc_no_left_paren_in_sql_returns_0(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); register_findc(db); /* Not a CREATE TABLE statement, and no '(' token before TK_ILLEGAL */ const char *sql = "DROP TABLE t;"; assert_findc_result(db, sql, "c1", SQLITE_INTEGER, 0); sqlite3_close(db); } static void test_findConstraintFunc_null_arguments_return_null(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); register_findc(db); /* NULL SQL input */ assert_findc_result(db, NULL, "c1", SQLITE_NULL, 0); /* NULL constraint name input */ const char *sql = "CREATE TABLE t ( a INT, CONSTRAINT c1 CHECK(a>0) );"; assert_findc_result(db, sql, NULL, SQLITE_NULL, 0); /* Both NULL */ assert_findc_result(db, NULL, NULL, SQLITE_NULL, 0); sqlite3_close(db); } static void test_findConstraintFunc_multiple_constraints_both_detected(void){ sqlite3 *db = 0; TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db)); register_findc(db); const char *sql = "CREATE TABLE t (" " a INT, b INT," " CONSTRAINT cA CHECK(a>0)," " CONSTRAINT cB UNIQUE(b)" ");"; assert_findc_result(db, sql, "cA", SQLITE_INTEGER, 1); assert_findc_result(db, sql, "ca", SQLITE_INTEGER, 1); /* case-insensitive */ assert_findc_result(db, sql, "cB", SQLITE_INTEGER, 1); assert_findc_result(db, sql, "cb", SQLITE_INTEGER, 1); assert_findc_result(db, sql, "nope", SQLITE_INTEGER, 0); sqlite3_close(db); } int main(void){ UNITY_BEGIN(); RUN_TEST(test_findConstraintFunc_basic_match); RUN_TEST(test_findConstraintFunc_case_insensitive_and_quoted); RUN_TEST(test_findConstraintFunc_bracket_and_backtick_quoted); RUN_TEST(test_findConstraintFunc_with_comments_and_nested_parens); RUN_TEST(test_findConstraintFunc_no_named_constraints_returns_0); RUN_TEST(test_findConstraintFunc_no_left_paren_in_sql_returns_0); RUN_TEST(test_findConstraintFunc_null_arguments_return_null); RUN_TEST(test_findConstraintFunc_multiple_constraints_both_detected); return UNITY_END(); }