AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdio.h>4#include <string.h>5 6/* Forward declaration of the function under test (in case not in headers) */7void sqlite3ResetAllSchemasOfConnection(sqlite3 *db);8 9static void exec_ok(sqlite3 *db, const char *sql){10 char *zErr = 0;11 int rc = sqlite3_exec(db, sql, 0, 0, &zErr);12 if( rc!=SQLITE_OK ){13 if( zErr ){14 fprintf(stderr, "SQL error: %s\n", zErr);15 sqlite3_free(zErr);16 }17 }18 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);19}20 21static int tbl_count(sqlite3 *db, int iDb){22 Schema *pSchema = db->aDb[iDb].pSchema;23 if( pSchema==0 ) return -1;24 return pSchema->tblHash.count;25}26 27void setUp(void) {28 /* no-op */29}30 31void tearDown(void) {32 /* no-op */33}34 35/* Test 1: When unlocked, schemas are cleared and DB flags are cleared */36void test_sqlite3ResetAllSchemasOfConnection_clears_schema_and_flags_no_lock(void){37 sqlite3 *db = 0;38 int rc = sqlite3_open(":memory:", &db);39 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);40 TEST_ASSERT_NOT_NULL(db);41 42 /* Create an object in main schema so that schema is populated */43 exec_ok(db, "CREATE TABLE t1(a);");44 45 /* Sanity: schema should have at least one table */46 TEST_ASSERT_TRUE(tbl_count(db, 0) > 0);47 48 /* Set flags that should be cleared by the function */49 db->mDbFlags |= (DBFLAG_SchemaChange | DBFLAG_SchemaKnownOk);50 51 /* Ensure unlocked */52 db->nSchemaLock = 0;53 54 sqlite3ResetAllSchemasOfConnection(db);55 56 /* After reset with no lock, schema hashes should be cleared */57 TEST_ASSERT_EQUAL_INT(0, tbl_count(db, 0));58 59 /* Flags should be cleared */60 TEST_ASSERT_EQUAL_INT(0, db->mDbFlags & (DBFLAG_SchemaChange | DBFLAG_SchemaKnownOk));61 62 sqlite3_close(db);63}64 65/* Test 2: When locked, schemas are not cleared, DB_ResetWanted is set, and nDb unchanged */66void test_sqlite3ResetAllSchemasOfConnection_sets_reset_wanted_when_locked(void){67 sqlite3 *db = 0;68 int rc = sqlite3_open(":memory:", &db);69 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);70 TEST_ASSERT_NOT_NULL(db);71 72 exec_ok(db, "CREATE TABLE t1(a);");73 74 int before = tbl_count(db, 0);75 TEST_ASSERT_TRUE(before > 0);76 77 /* Simulate lock to prevent schema clear */78 db->nSchemaLock = 1;79 80 /* Set flags that should be cleared regardless */81 db->mDbFlags |= (DBFLAG_SchemaChange | DBFLAG_SchemaKnownOk);82 83 int nDb_before = db->nDb;84 85 sqlite3ResetAllSchemasOfConnection(db);86 87 /* Schema should remain intact */88 TEST_ASSERT_EQUAL_INT(before, tbl_count(db, 0));89 90 /* DB_ResetWanted property should be set for "main" db (index 0) */91 TEST_ASSERT_TRUE(DbHasProperty(db, 0, DB_ResetWanted));92 93 /* Number of dbs should not change when locked */94 TEST_ASSERT_EQUAL_INT(nDb_before, db->nDb);95 96 /* Flags should be cleared */97 TEST_ASSERT_EQUAL_INT(0, db->mDbFlags & (DBFLAG_SchemaChange | DBFLAG_SchemaKnownOk));98 99 sqlite3_close(db);100}101 102/* Test 3: Collapse removes entries with pBt == 0 from aDb[] when unlocked */103void test_sqlite3ResetAllSchemasOfConnection_collapses_database_array(void){104 sqlite3 *db = 0;105 int rc = sqlite3_open(":memory:", &db);106 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);107 TEST_ASSERT_NOT_NULL(db);108 109 /* Attach two databases to create entries at indices >= 2 */110 exec_ok(db, "ATTACH DATABASE ':memory:' AS aux1;");111 exec_ok(db, "ATTACH DATABASE ':memory:' AS aux2;");112 113 TEST_ASSERT_TRUE(db->nDb >= 4);114 115 /* Capture current pointers for verification */116 Db *pAux1 = &db->aDb[2];117 Db *pAux2 = &db->aDb[3];118 char *zAux1Name = pAux1->zDbSName;119 char *zAux2Name = pAux2->zDbSName;120 TEST_ASSERT_NOT_NULL(zAux1Name);121 TEST_ASSERT_NOT_NULL(zAux2Name);122 TEST_ASSERT_NOT_NULL(pAux1->pBt);123 TEST_ASSERT_NOT_NULL(pAux2->pBt);124 125 /* Simulate a closed/removed btree for aux1 so collapse removes it. */126 pAux1->pBt = 0;127 128 int nDb_before = db->nDb;129 130 /* Ensure unlocked so collapse runs */131 db->nSchemaLock = 0;132 133 sqlite3ResetAllSchemasOfConnection(db);134 135 /* One entry should have been removed (aux1) */136 TEST_ASSERT_EQUAL_INT(nDb_before - 1, db->nDb);137 138 /* The entry at index 2 should now be the previous aux2 */139 TEST_ASSERT_EQUAL_PTR(zAux2Name, db->aDb[2].zDbSName);140 141 /* Sanity: removed entry's name pointer should no longer be present at index 2 */142 TEST_ASSERT_TRUE(db->aDb[2].zDbSName != zAux1Name);143 144 sqlite3_close(db);145}146 147int main(void) {148 UNITY_BEGIN();149 RUN_TEST(test_sqlite3ResetAllSchemasOfConnection_clears_schema_and_flags_no_lock);150 RUN_TEST(test_sqlite3ResetAllSchemasOfConnection_sets_reset_wanted_when_locked);151 RUN_TEST(test_sqlite3ResetAllSchemasOfConnection_collapses_database_array);152 return UNITY_END();153}