AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdio.h>5 6/* Wrapper provided in the SQLite module for static function checkPtrmap */7extern void test_checkPtrmap(IntegrityCk *pCheck, Pgno iChild, u8 eType, Pgno iParent);8 9static void init_db_autovac(sqlite3 **ppDb){10 sqlite3 *db = 0;11 int rc = sqlite3_open("test_checkptrmap.db", &db);12 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);13 14 /* Enable full autovacuum and set a small page size for simplicity, then VACUUM */15 rc = sqlite3_exec(db, "PRAGMA auto_vacuum=FULL; PRAGMA page_size=1024;", 0, 0, 0);16 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);17 rc = sqlite3_exec(db, "VACUUM;", 0, 0, 0);18 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);19 20 *ppDb = db;21}22 23static Pgno get_table_rootpage(sqlite3 *db, const char *zName){24 sqlite3_stmt *stmt = 0;25 Pgno root = 0;26 int rc = sqlite3_prepare_v2(db, "SELECT rootpage FROM sqlite_schema WHERE name=?1;", -1, &stmt, 0);27 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);28 rc = sqlite3_bind_text(stmt, 1, zName, -1, SQLITE_STATIC);29 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);30 rc = sqlite3_step(stmt);31 TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);32 root = (Pgno)sqlite3_column_int(stmt, 0);33 sqlite3_finalize(stmt);34 return root;35}36 37static void init_integrity_ck(IntegrityCk *pCk, sqlite3 *db, BtShared *pBt, char *zBuf, int nBuf){38 memset(pCk, 0, sizeof(*pCk));39 pCk->db = db;40 pCk->pBt = pBt;41 pCk->pPager = pBt->pPager;42 pCk->mxErr = 1000;43 sqlite3StrAccumInit(&pCk->errMsg, 0, zBuf, nBuf, SQLITE_MAX_LENGTH);44 pCk->errMsg.printfFlags = SQLITE_PRINTF_INTERNAL;45}46 47/* Unity hooks */48void setUp(void) {49 /* nothing */50}51void tearDown(void) {52 /* remove db file to avoid cross-test contamination */53 sqlite3_vfs *pVfs = sqlite3_vfs_find(0);54 if( pVfs ){55 sqlite3_file *pFile = (sqlite3_file*)sqlite3_malloc(pVfs->szOsFile);56 if( pFile ){57 if( pVfs->xAccess ){58 /* Ignore result; file may not exist */59 }60 if( pVfs->xDelete ){61 pVfs->xDelete(pVfs, "test_checkptrmap.db", 0);62 }63 sqlite3_free(pFile);64 }65 }66}67 68/* Test: correct mapping for a root page should produce no error */69void test_checkPtrmap_root_ok(void){70 sqlite3 *db = 0;71 init_db_autovac(&db);72 73 /* Create a table and get its root page */74 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_exec(db, "CREATE TABLE t(a);", 0, 0, 0));75 Pgno root = get_table_rootpage(db, "t");76 TEST_ASSERT_GREATER_THAN_UINT32(1u, 0u); /* dummy to keep compiler happy */77 78 /* Acquire Btree and BtShared */79 Btree *pBtree = db->aDb[0].pBt;80 TEST_ASSERT_NOT_NULL(pBtree);81 BtShared *pBt = pBtree->pBt;82 TEST_ASSERT_NOT_NULL(pBt);83 84 /* Prepare integrity checker context */85 char zBuf[1024];86 IntegrityCk ck;87 init_integrity_ck(&ck, db, pBt, zBuf, (int)sizeof(zBuf));88 89 /* Must hold the btree mutex while invoking checkPtrmap */90 sqlite3BtreeEnter(pBtree);91 test_checkPtrmap(&ck, root, PTRMAP_ROOTPAGE, 0);92 sqlite3BtreeLeave(pBtree);93 94 /* Expect no errors */95 TEST_ASSERT_EQUAL_INT(0, ck.nErr);96 97 sqlite3_close(db);98}99 100/* Test: wrong expected type for a valid root page should report an error */101void test_checkPtrmap_root_wrong_type_reports_error(void){102 sqlite3 *db = 0;103 init_db_autovac(&db);104 105 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_exec(db, "CREATE TABLE t(a);", 0, 0, 0));106 Pgno root = get_table_rootpage(db, "t");107 108 Btree *pBtree = db->aDb[0].pBt;109 TEST_ASSERT_NOT_NULL(pBtree);110 BtShared *pBt = pBtree->pBt;111 TEST_ASSERT_NOT_NULL(pBt);112 113 char zBuf[1024];114 IntegrityCk ck;115 init_integrity_ck(&ck, db, pBt, zBuf, (int)sizeof(zBuf));116 117 sqlite3BtreeEnter(pBtree);118 /* Supply wrong expected type */119 test_checkPtrmap(&ck, root, PTRMAP_FREEPAGE, 0);120 sqlite3BtreeLeave(pBtree);121 122 TEST_ASSERT_GREATER_THAN_INT(0, ck.nErr);123 /* The error message should contain "Bad ptr map entry" */124 TEST_ASSERT_NOT_NULL(ck.errMsg.zText);125 TEST_ASSERT_GREATER_OR_EQUAL_INT(0, (int)strstr(ck.errMsg.zText, "Bad ptr map entry") - ck.errMsg.zText);126 127 sqlite3_close(db);128}129 130/* Test: mapping for a freed page (after dropping a table) should be FREEPAGE, parent 0 */131void test_checkPtrmap_freepage_ok(void){132 sqlite3 *db = 0;133 init_db_autovac(&db);134 135 /* Create and drop a table t2 to put its root page onto the freelist */136 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_exec(db, "CREATE TABLE t2(x);", 0, 0, 0));137 Pgno root2 = get_table_rootpage(db, "t2");138 TEST_ASSERT_GREATER_THAN_UINT32(2u, 0u);139 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_exec(db, "DROP TABLE t2;", 0, 0, 0));140 141 Btree *pBtree = db->aDb[0].pBt;142 TEST_ASSERT_NOT_NULL(pBtree);143 BtShared *pBt = pBtree->pBt;144 TEST_ASSERT_NOT_NULL(pBt);145 146 char zBuf[1024];147 IntegrityCk ck;148 init_integrity_ck(&ck, db, pBt, zBuf, (int)sizeof(zBuf));149 150 sqlite3BtreeEnter(pBtree);151 test_checkPtrmap(&ck, root2, PTRMAP_FREEPAGE, 0);152 sqlite3BtreeLeave(pBtree);153 154 TEST_ASSERT_EQUAL_INT(0, ck.nErr);155 156 sqlite3_close(db);157}158 159/* Test: wrong expected parent for FREEPAGE should report error */160void test_checkPtrmap_freepage_wrong_parent_reports_error(void){161 sqlite3 *db = 0;162 init_db_autovac(&db);163 164 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_exec(db, "CREATE TABLE t2(x);", 0, 0, 0));165 Pgno root2 = get_table_rootpage(db, "t2");166 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_exec(db, "DROP TABLE t2;", 0, 0, 0));167 168 Btree *pBtree = db->aDb[0].pBt;169 TEST_ASSERT_NOT_NULL(pBtree);170 BtShared *pBt = pBtree->pBt;171 TEST_ASSERT_NOT_NULL(pBt);172 173 char zBuf[1024];174 IntegrityCk ck;175 init_integrity_ck(&ck, db, pBt, zBuf, (int)sizeof(zBuf));176 177 sqlite3BtreeEnter(pBtree);178 /* Supply incorrect expected parent (FREEPAGE entries have parent 0) */179 test_checkPtrmap(&ck, root2, PTRMAP_FREEPAGE, 999999);180 sqlite3BtreeLeave(pBtree);181 182 TEST_ASSERT_GREATER_THAN_INT(0, ck.nErr);183 TEST_ASSERT_NOT_NULL(ck.errMsg.zText);184 TEST_ASSERT_GREATER_OR_EQUAL_INT(0, (int)strstr(ck.errMsg.zText, "Bad ptr map entry") - ck.errMsg.zText);185 186 sqlite3_close(db);187}188 189int main(void){190 UNITY_BEGIN();191 RUN_TEST(test_checkPtrmap_root_ok);192 RUN_TEST(test_checkPtrmap_root_wrong_type_reports_error);193 RUN_TEST(test_checkPtrmap_freepage_ok);194 RUN_TEST(test_checkPtrmap_freepage_wrong_parent_reports_error);195 return UNITY_END();196}