AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* External wrapper provided in the source under test */7extern int test_sqlite3Prepare(sqlite3 *db, const char *zSql, int nBytes,8 u32 prepFlags, Vdbe *pReprepare,9 sqlite3_stmt **ppStmt, const char **pzTail);10 11/* Helper to call the internal prepare with required locks held */12static int call_prepare(sqlite3 *db, const char *zSql, int nBytes, u32 prepFlags,13 Vdbe *pReprepare, sqlite3_stmt **ppStmt, const char **pzTail){14 int rc;15 sqlite3_mutex_enter(db->mutex);16 sqlite3BtreeEnterAll(db);17 rc = test_sqlite3Prepare(db, zSql, nBytes, prepFlags, pReprepare, ppStmt, pzTail);18 sqlite3BtreeLeaveAll(db);19 sqlite3_mutex_leave(db->mutex);20 return rc;21}22 23static sqlite3 *gDb = NULL;24 25void setUp(void) {26 int rc = sqlite3_open(":memory:", &gDb);27 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "Failed to open in-memory SQLite DB");28}29 30void tearDown(void) {31 if( gDb ){32 int rc = sqlite3_close(gDb);33 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "Failed to close SQLite DB");34 gDb = NULL;35 }36}37 38/* Utility to finalize and null-out a statement pointer if non-NULL */39static void finalize_if(sqlite3_stmt **ppStmt){40 if( ppStmt && *ppStmt ){41 sqlite3_finalize(*ppStmt);42 *ppStmt = NULL;43 }44}45 46void test_sqlite3Prepare_basic_ok(void) {47 const char *sql = "SELECT 1;";48 sqlite3_stmt *pStmt = NULL;49 const char *zTail = NULL;50 51 int rc = call_prepare(gDb, sql, -1, 0, NULL, &pStmt, &zTail);52 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);53 TEST_ASSERT_NOT_NULL(pStmt);54 TEST_ASSERT_NOT_NULL(zTail);55 TEST_ASSERT_EQUAL_CHAR('\0', *zTail);56 57 finalize_if(&pStmt);58}59 60void test_sqlite3Prepare_tail_for_next_stmt(void) {61 const char *sql = "SELECT 1;SELECT 2;";62 sqlite3_stmt *pStmt = NULL;63 const char *zTail = NULL;64 65 int rc = call_prepare(gDb, sql, -1, 0, NULL, &pStmt, &zTail);66 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);67 TEST_ASSERT_NOT_NULL(pStmt);68 TEST_ASSERT_NOT_NULL(zTail);69 /* Expect tail to point at the start of the second statement */70 TEST_ASSERT_EQUAL_INT(0, strncmp(zTail, "SELECT 2;", 9));71 72 finalize_if(&pStmt);73}74 75void test_sqlite3Prepare_with_nBytes_substring(void) {76 /* Provide extra bytes after the first statement and specify nBytes to end at ';' */77 char sql[] = "SELECT 1;XYZ";78 int nBytes = (int)strlen("SELECT 1;"); /* Truncate before the 'X' */79 sqlite3_stmt *pStmt = NULL;80 const char *zTail = NULL;81 82 int rc = call_prepare(gDb, sql, nBytes, 0, NULL, &pStmt, &zTail);83 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);84 TEST_ASSERT_NOT_NULL(pStmt);85 TEST_ASSERT_NOT_NULL(zTail);86 /* Tail should map back into the original buffer at offset nBytes */87 TEST_ASSERT_EQUAL_PTR(sql + nBytes, zTail);88 TEST_ASSERT_EQUAL_CHAR('X', *zTail);89 90 finalize_if(&pStmt);91}92 93void test_sqlite3Prepare_invalid_sql_returns_error(void) {94 const char *sql = "SELEC 1;"; /* Intentionally invalid (missing 'T') */95 sqlite3_stmt *pStmt = NULL;96 const char *zTail = NULL;97 98 int rc = call_prepare(gDb, sql, -1, 0, NULL, &pStmt, &zTail);99 TEST_ASSERT_NOT_EQUAL(SQLITE_OK, rc);100 TEST_ASSERT_NULL(pStmt);101 /* zTail may be set by the parser; not asserting a specific value here */102}103 104void test_sqlite3Prepare_empty_sql_ok_no_stmt(void) {105 const char *sql = " \n\t";106 sqlite3_stmt *pStmt = NULL;107 const char *zTail = NULL;108 109 int rc = call_prepare(gDb, sql, -1, 0, NULL, &pStmt, &zTail);110 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);111 TEST_ASSERT_NULL(pStmt);112 TEST_ASSERT_NOT_NULL(zTail);113 TEST_ASSERT_EQUAL_CHAR('\0', *zTail);114}115 116void test_sqlite3Prepare_persistent_flag_ok(void) {117 const char *sql = "SELECT 1;";118 sqlite3_stmt *pStmt = NULL;119 const char *zTail = NULL;120 121 int rc = call_prepare(gDb, sql, -1, SQLITE_PREPARE_PERSISTENT, NULL, &pStmt, &zTail);122 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);123 TEST_ASSERT_NOT_NULL(pStmt);124 TEST_ASSERT_NOT_NULL(zTail);125 TEST_ASSERT_EQUAL_CHAR('\0', *zTail);126 127 finalize_if(&pStmt);128}129 130void test_sqlite3Prepare_with_reprepare_handle(void) {131 /* Prepare a statement using the public API, then pass it as pReprepare */132 const char *sql = "SELECT 1;";133 sqlite3_stmt *pExisting = NULL;134 int rc = sqlite3_prepare_v2(gDb, sql, -1, &pExisting, NULL);135 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);136 TEST_ASSERT_NOT_NULL(pExisting);137 138 sqlite3_stmt *pNew = NULL;139 const char *zTail = NULL;140 rc = call_prepare(gDb, sql, -1, 0, (Vdbe*)pExisting, &pNew, &zTail);141 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);142 TEST_ASSERT_NOT_NULL(pNew);143 TEST_ASSERT_NOT_NULL(zTail);144 TEST_ASSERT_EQUAL_CHAR('\0', *zTail);145 146 finalize_if(&pExisting);147 finalize_if(&pNew);148}149 150void test_sqlite3Prepare_null_tail_parameter(void) {151 const char *sql = "SELECT 42;";152 sqlite3_stmt *pStmt = NULL;153 154 int rc = call_prepare(gDb, sql, -1, 0, NULL, &pStmt, NULL);155 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);156 TEST_ASSERT_NOT_NULL(pStmt);157 158 finalize_if(&pStmt);159}160 161int main(void) {162 UNITY_BEGIN();163 RUN_TEST(test_sqlite3Prepare_basic_ok);164 RUN_TEST(test_sqlite3Prepare_tail_for_next_stmt);165 RUN_TEST(test_sqlite3Prepare_with_nBytes_substring);166 RUN_TEST(test_sqlite3Prepare_invalid_sql_returns_error);167 RUN_TEST(test_sqlite3Prepare_empty_sql_ok_no_stmt);168 RUN_TEST(test_sqlite3Prepare_persistent_flag_ok);169 RUN_TEST(test_sqlite3Prepare_with_reprepare_handle);170 RUN_TEST(test_sqlite3Prepare_null_tail_parameter);171 return UNITY_END();172}