File size: 7,946 Bytes
7510827 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
#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();
} |