sqlite / tests /tests_alter_renameFixQuotes.c
AryaWu's picture
Upload folder using huggingface_hub
7510827 verified
#include "sqliteInt.h"
#include "unity.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/* Wrapper provided externally for static function under test */
extern void test_renameFixQuotes(Parse *pParse, const char *zDb, int bTemp);
/* Utility: execute SQL and assert success */
static void exec_sql_ok(sqlite3 *db, const char *zSql){
char *zErr = 0;
int rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
if( rc!=SQLITE_OK ){
/* Provide error context in assertion message */
const char *msg = zErr ? zErr : "no message";
/* Free error before assertion to avoid leak */
if( zErr ) sqlite3_free(zErr);
TEST_FAIL_MESSAGE(msg);
}
if( zErr ) sqlite3_free(zErr);
}
/* Utility: fetch the sql text from "<zDb>." LEGACY_SCHEMA_TABLE " where name=<zName>".
** Returns a heap-allocated copy using sqlite3_mprintf; caller must sqlite3_free().
*/
static char *get_schema_sql(sqlite3 *db, const char *zDb, const char *zName){
char *zSql = sqlite3_mprintf(
"SELECT sql FROM \"%w\"." LEGACY_SCHEMA_TABLE " WHERE name=%Q",
zDb, zName
);
sqlite3_stmt *pStmt = 0;
char *zOut = 0;
int rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc!=SQLITE_OK ){
TEST_FAIL_MESSAGE("prepare failed in get_schema_sql");
return 0;
}
rc = sqlite3_step(pStmt);
if( rc==SQLITE_ROW ){
const unsigned char *z = sqlite3_column_text(pStmt, 0);
if( z ){
zOut = sqlite3_mprintf("%s", z);
}else{
zOut = 0;
}
}else{
/* No such row found */
zOut = 0;
}
sqlite3_finalize(pStmt);
return zOut;
}
/* Helpers to check substring presence */
static int contains(const char *hay, const char *needle){
if( hay==0 || needle==0 ) return 0;
return strstr(hay, needle)!=0;
}
void setUp(void) {
/* nothing */
}
void tearDown(void) {
/* nothing */
}
/* Test: When bTemp==1, only the specified database (main) is updated; temp is not. */
void test_renameFixQuotes_updates_only_main_when_bTemp_is_true(void){
sqlite3 *db = 0;
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));
/* Create main objects with double-quoted string literal in SQL */
exec_sql_ok(db, "CREATE TABLE t1(x);");
exec_sql_ok(db, "CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO t1 VALUES(\"abc\"); END;");
/* Create temp objects with double-quoted string literal in SQL */
exec_sql_ok(db, "CREATE TEMP TABLE tt1(x);");
exec_sql_ok(db, "CREATE TEMP TRIGGER trtemp AFTER INSERT ON tt1 BEGIN INSERT INTO tt1 VALUES(\"def\"); END;");
/* Precondition checks */
char *zMainTrig = get_schema_sql(db, "main", "tr1");
char *zTempTrig = get_schema_sql(db, "temp", "trtemp");
TEST_ASSERT_NOT_NULL(zMainTrig);
TEST_ASSERT_NOT_NULL(zTempTrig);
TEST_ASSERT_TRUE_MESSAGE(contains(zMainTrig, "VALUES(\"abc\")"), "Main trigger SQL missing expected double-quoted literal");
TEST_ASSERT_TRUE_MESSAGE(contains(zTempTrig, "VALUES(\"def\")"), "Temp trigger SQL missing expected double-quoted literal");
sqlite3_free(zMainTrig);
sqlite3_free(zTempTrig);
/* Call function under test: update only main (bTemp==1) */
Parse sParse;
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
test_renameFixQuotes(&sParse, "main", 1);
/* Postcondition: main updated to single-quoted; temp unchanged */
zMainTrig = get_schema_sql(db, "main", "tr1");
zTempTrig = get_schema_sql(db, "temp", "trtemp");
TEST_ASSERT_NOT_NULL(zMainTrig);
TEST_ASSERT_NOT_NULL(zTempTrig);
TEST_ASSERT_TRUE_MESSAGE(contains(zMainTrig, "VALUES('abc')"), "Main trigger SQL was not converted to single quotes");
TEST_ASSERT_FALSE_MESSAGE(contains(zMainTrig, "VALUES(\"abc\")"), "Main trigger SQL still contains double-quoted literal");
TEST_ASSERT_TRUE_MESSAGE(contains(zTempTrig, "VALUES(\"def\")"), "Temp trigger SQL should remain with double-quoted literal when bTemp==1");
TEST_ASSERT_FALSE_MESSAGE(contains(zTempTrig, "VALUES('def')"), "Temp trigger SQL should not be converted when bTemp==1");
sqlite3_free(zMainTrig);
sqlite3_free(zTempTrig);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));
}
/* Test: When bTemp==0, both the specified database (main) and temp are updated. */
void test_renameFixQuotes_updates_main_and_temp_when_bTemp_is_false(void){
sqlite3 *db = 0;
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));
exec_sql_ok(db, "CREATE TABLE t1(x);");
exec_sql_ok(db, "CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO t1 VALUES(\"abc\"); END;");
exec_sql_ok(db, "CREATE TEMP TABLE tt1(x);");
exec_sql_ok(db, "CREATE TEMP TRIGGER trtemp AFTER INSERT ON tt1 BEGIN INSERT INTO tt1 VALUES(\"def\"); END;");
/* Precondition sanity */
char *zMainTrig = get_schema_sql(db, "main", "tr1");
char *zTempTrig = get_schema_sql(db, "temp", "trtemp");
TEST_ASSERT_NOT_NULL(zMainTrig);
TEST_ASSERT_NOT_NULL(zTempTrig);
TEST_ASSERT_TRUE(contains(zMainTrig, "VALUES(\"abc\")"));
TEST_ASSERT_TRUE(contains(zTempTrig, "VALUES(\"def\")"));
sqlite3_free(zMainTrig);
sqlite3_free(zTempTrig);
/* Call function under test: update main and temp (bTemp==0) */
Parse sParse;
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
test_renameFixQuotes(&sParse, "main", 0);
/* Postcondition: both main and temp converted */
zMainTrig = get_schema_sql(db, "main", "tr1");
zTempTrig = get_schema_sql(db, "temp", "trtemp");
TEST_ASSERT_NOT_NULL(zMainTrig);
TEST_ASSERT_NOT_NULL(zTempTrig);
TEST_ASSERT_TRUE(contains(zMainTrig, "VALUES('abc')"));
TEST_ASSERT_FALSE(contains(zMainTrig, "VALUES(\"abc\")"));
TEST_ASSERT_TRUE(contains(zTempTrig, "VALUES('def')"));
TEST_ASSERT_FALSE(contains(zTempTrig, "VALUES(\"def\")"));
sqlite3_free(zMainTrig);
sqlite3_free(zTempTrig);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));
}
/* Test: Other attached databases are not affected when zDb is "main". */
void test_renameFixQuotes_does_not_affect_other_attached_db(void){
sqlite3 *db = 0;
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));
/* Main schema objects */
exec_sql_ok(db, "CREATE TABLE t1(x);");
exec_sql_ok(db, "CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO t1 VALUES(\"abc\"); END;");
/* Attach another database and create an object with double-quoted literal */
/* Use on-disk temp file for portability */
exec_sql_ok(db, "ATTACH 'test_aux.db' AS aux;");
exec_sql_ok(db, "CREATE TABLE aux.t2(y);");
exec_sql_ok(db, "CREATE TRIGGER aux.tr2 AFTER INSERT ON t2 BEGIN INSERT INTO t2 VALUES(\"ghi\"); END;");
/* Sanity preconditions */
char *zMainTrig = get_schema_sql(db, "main", "tr1");
char *zAuxTrig = get_schema_sql(db, "aux", "tr2");
TEST_ASSERT_NOT_NULL(zMainTrig);
TEST_ASSERT_NOT_NULL(zAuxTrig);
TEST_ASSERT_TRUE(contains(zMainTrig, "VALUES(\"abc\")"));
TEST_ASSERT_TRUE(contains(zAuxTrig, "VALUES(\"ghi\")"));
sqlite3_free(zMainTrig);
sqlite3_free(zAuxTrig);
/* Call function under test for "main"; do not update temp for this test */
Parse sParse;
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
test_renameFixQuotes(&sParse, "main", 1);
/* Verify main updated, aux unchanged */
zMainTrig = get_schema_sql(db, "main", "tr1");
zAuxTrig = get_schema_sql(db, "aux", "tr2");
TEST_ASSERT_NOT_NULL(zMainTrig);
TEST_ASSERT_NOT_NULL(zAuxTrig);
TEST_ASSERT_TRUE(contains(zMainTrig, "VALUES('abc')"));
TEST_ASSERT_FALSE(contains(zMainTrig, "VALUES(\"abc\")"));
TEST_ASSERT_TRUE(contains(zAuxTrig, "VALUES(\"ghi\")"));
TEST_ASSERT_FALSE(contains(zAuxTrig, "VALUES('ghi')"));
sqlite3_free(zMainTrig);
sqlite3_free(zAuxTrig);
/* Cleanup */
exec_sql_ok(db, "DETACH aux;");
TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));
}
int main(void){
UNITY_BEGIN();
RUN_TEST(test_renameFixQuotes_updates_only_main_when_bTemp_is_true);
RUN_TEST(test_renameFixQuotes_updates_main_and_temp_when_bTemp_is_false);
RUN_TEST(test_renameFixQuotes_does_not_affect_other_attached_db);
return UNITY_END();
}