sqlite / tests /tests_alter_renameEditSql.c
AryaWu's picture
Upload folder using huggingface_hub
7510827 verified
#include "sqliteInt.h"
#include "unity.h"
#include <string.h>
#include <stdio.h>
/* Wrapper for the static function under test (provided by the module). */
extern int test_renameEditSql(
sqlite3_context *pCtx,
RenameCtx *pRename,
const char *zSql,
const char *zNew,
int bQuote
);
/* Helper: add a RenameToken covering the span [start, start+n) within zSql. */
static void addTokenSpan(sqlite3 *db, RenameCtx *p, const char *zSql, int start, int n){
RenameToken *pTok = (RenameToken*)sqlite3DbMallocZero(db, sizeof(RenameToken));
TEST_ASSERT_NOT_NULL_MESSAGE(pTok, "Failed to allocate RenameToken");
pTok->t.z = zSql + start;
pTok->t.n = n;
pTok->pNext = p->pList;
p->pList = pTok;
p->nList++;
}
/* Helper: find and add token for the first occurrence of substring sub in zSql. */
static void addTokenForSubstring(sqlite3 *db, RenameCtx *p, const char *zSql, const char *sub){
const char *pos = strstr(zSql, sub);
TEST_ASSERT_NOT_NULL_MESSAGE(pos, "Substring not found in SQL");
int start = (int)(pos - zSql);
addTokenSpan(db, p, zSql, start, (int)strlen(sub));
}
/* Helper: initialize a sqlite3_context that can be used by renameEditSql */
static void initContext(sqlite3_context *pCtx, sqlite3 *db, Vdbe *pVdbe){
memset(pCtx, 0, sizeof(*pCtx));
memset(pVdbe, 0, sizeof(*pVdbe));
pVdbe->db = db;
pCtx->pVdbe = pVdbe;
sqlite3VdbeMemInit(&pCtx->s, db, 0);
}
/* Helper: call test_renameEditSql and fetch result string from context.
Returns rc and sets *pzOut to point to the Mem string (owned by pCtx->s). */
static int call_and_result(sqlite3 *db, RenameCtx *pRename, const char *zSql,
const char *zNew, int bQuote, char const **pzOut){
sqlite3_context ctx;
Vdbe vdbe;
initContext(&ctx, db, &vdbe);
int rc = test_renameEditSql(&ctx, pRename, zSql, zNew, bQuote);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
TEST_ASSERT_NOT_NULL_MESSAGE(ctx.s.z, "No result text produced");
*pzOut = (const char*)ctx.s.z;
/* We intentionally do not release ctx.s here to allow caller to inspect it.
Caller must call sqlite3VdbeMemRelease on a copy of the Mem. */
/* Make a shallow copy of Mem to release after check */
Mem sCopy = ctx.s;
/* Zero original to avoid double-free after release of sCopy */
memset(&ctx.s, 0, sizeof(ctx.s));
sqlite3VdbeMemRelease(&sCopy);
return rc;
}
void setUp(void) {
/* Setup code here, or leave empty */
}
void tearDown(void) {
/* Cleanup code here, or leave empty */
}
/* Test 1: Basic unquoted replacement with multiple tokens. */
void test_renameEditSql_basic_unquoted_multiple(void){
sqlite3 *db = 0;
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));
const char *zSql = "CREATE TABLE t (old, b, old);";
RenameCtx ctxRename;
memset(&ctxRename, 0, sizeof(ctxRename));
/* Add both occurrences of "old" as tokens (add in reverse order to
test that order of pList is not required to be sorted). */
const char *first = strstr(zSql, "old");
const char *second = strstr(first+1, "old");
TEST_ASSERT_NOT_NULL(first);
TEST_ASSERT_NOT_NULL(second);
addTokenSpan(db, &ctxRename, zSql, (int)(second - zSql), 3);
addTokenSpan(db, &ctxRename, zSql, (int)(first - zSql), 3);
const char *zNew = "newname";
const char *zOut = NULL;
call_and_result(db, &ctxRename, zSql, zNew, 0, &zOut);
TEST_ASSERT_EQUAL_STRING("CREATE TABLE t (newname, b, newname);", zOut);
/* The function should have consumed all tokens */
TEST_ASSERT_NULL(ctxRename.pList);
sqlite3_close(db);
}
/* Test 2: Force quoting with bQuote==1. */
void test_renameEditSql_force_quote_bQuote1(void){
sqlite3 *db = 0;
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));
const char *zSql = "CREATE TABLE t (old);";
RenameCtx ctxRename;
memset(&ctxRename, 0, sizeof(ctxRename));
addTokenForSubstring(db, &ctxRename, zSql, "old");
const char *zNew = "col name"; /* requires quoting */
const char *zOut = NULL;
call_and_result(db, &ctxRename, zSql, zNew, 1, &zOut);
TEST_ASSERT_EQUAL_STRING("CREATE TABLE t (\"col name\");", zOut);
TEST_ASSERT_NULL(ctxRename.pList);
sqlite3_close(db);
}
/* Test 3: Original token is quoted, bQuote==0 still results in quoted replacement. */
void test_renameEditSql_quoted_input_bQuote0(void){
sqlite3 *db = 0;
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));
const char *zSql = "SELECT \"old\" FROM t;";
RenameCtx ctxRename;
memset(&ctxRename, 0, sizeof(ctxRename));
addTokenForSubstring(db, &ctxRename, zSql, "\"old\"");
const char *zNew = "foo";
const char *zOut = NULL;
call_and_result(db, &ctxRename, zSql, zNew, 0, &zOut);
TEST_ASSERT_EQUAL_STRING("SELECT \"foo\" FROM t;", zOut);
TEST_ASSERT_NULL(ctxRename.pList);
sqlite3_close(db);
}
/* Test 4: zNew==NULL converts double-quoted token to single-quoted text and
inserts a space if immediately followed by a single-quote. */
void test_renameEditSql_null_zNew_single_quote_conversion_with_space(void){
sqlite3 *db = 0;
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));
/* Case with following single-quote -> space should be inserted */
{
const char *zSql = "SELECT \"string\"'alias'";
RenameCtx ctxRename;
memset(&ctxRename, 0, sizeof(ctxRename));
addTokenForSubstring(db, &ctxRename, zSql, "\"string\"");
const char *zOut = NULL;
call_and_result(db, &ctxRename, zSql, NULL, 0, &zOut);
TEST_ASSERT_EQUAL_STRING("SELECT 'string' 'alias'", zOut);
TEST_ASSERT_NULL(ctxRename.pList);
}
/* Case without following single-quote -> no extra space */
{
const char *zSql = "SELECT \"data\";";
RenameCtx ctxRename;
memset(&ctxRename, 0, sizeof(ctxRename));
addTokenForSubstring(db, &ctxRename, zSql, "\"data\"");
const char *zOut = NULL;
call_and_result(db, &ctxRename, zSql, NULL, 0, &zOut);
TEST_ASSERT_EQUAL_STRING("SELECT 'data';", zOut);
TEST_ASSERT_NULL(ctxRename.pList);
}
sqlite3_close(db);
}
/* Test 5: No tokens -> SQL should be returned unchanged (zNew non-NULL). */
void test_renameEditSql_no_tokens_sql_unchanged(void){
sqlite3 *db = 0;
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));
const char *zSql = "CREATE VIEW v AS SELECT a, b FROM t;";
RenameCtx ctxRename;
memset(&ctxRename, 0, sizeof(ctxRename));
const char *zOut = NULL;
call_and_result(db, &ctxRename, zSql, "x", 0, &zOut);
TEST_ASSERT_EQUAL_STRING(zSql, zOut);
TEST_ASSERT_NULL(ctxRename.pList);
sqlite3_close(db);
}
/* Test 6: Multiple tokens out-of-order in pList, ensure all replaced correctly. */
void test_renameEditSql_multiple_tokens_out_of_order(void){
sqlite3 *db = 0;
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));
const char *zSql = "UPDATE t SET old = 1, x = old, y = old;";
RenameCtx ctxRename;
memset(&ctxRename, 0, sizeof(ctxRename));
/* Find three occurrences of "old" and add them in jumbled order */
const char *p = zSql;
int offs[3];
for(int i=0;i<3;i++){
p = strstr(p, "old");
TEST_ASSERT_NOT_NULL(p);
offs[i] = (int)(p - zSql);
p += 3;
}
/* Add in order 2,0,1 */
addTokenSpan(db, &ctxRename, zSql, offs[2], 3);
addTokenSpan(db, &ctxRename, zSql, offs[0], 3);
addTokenSpan(db, &ctxRename, zSql, offs[1], 3);
const char *zOut = NULL;
call_and_result(db, &ctxRename, zSql, "nn", 0, &zOut);
TEST_ASSERT_EQUAL_STRING("UPDATE t SET nn = 1, x = nn, y = nn;", zOut);
TEST_ASSERT_NULL(ctxRename.pList);
sqlite3_close(db);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_renameEditSql_basic_unquoted_multiple);
RUN_TEST(test_renameEditSql_force_quote_bQuote1);
RUN_TEST(test_renameEditSql_quoted_input_bQuote0);
RUN_TEST(test_renameEditSql_null_zNew_single_quote_conversion_with_space);
RUN_TEST(test_renameEditSql_no_tokens_sql_unchanged);
RUN_TEST(test_renameEditSql_multiple_tokens_out_of_order);
return UNITY_END();
}