AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Helper stress callback for PCache - not used in these tests but required by open */7static int testStressCb(void *p, PgHdr *pPg){8 (void)p; (void)pPg;9 return SQLITE_OK;10}11 12static PCache* helperCreateCache(int pageSize){13 int rc;14 void *mem = sqlite3_malloc(sqlite3PcacheSize());15 TEST_ASSERT_NOT_NULL(mem);16 17 PCache *pCache = (PCache*)mem;18 rc = sqlite3PcacheOpen(pageSize, 64, 1, testStressCb, NULL, pCache);19 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);20 return pCache;21}22 23static void helperDestroyCache(PCache *pCache){24 if( pCache ){25 sqlite3PcacheClose(pCache);26 sqlite3_free(pCache);27 }28}29 30static PgHdr* helperFetchPage(PCache *pCache, Pgno pgno){31 sqlite3_pcache_page *pLower = sqlite3PcacheFetch(pCache, pgno, 3);32 TEST_ASSERT_NOT_NULL(pLower);33 PgHdr *pPg = sqlite3PcacheFetchFinish(pCache, pgno, pLower);34 TEST_ASSERT_NOT_NULL(pPg);35 return pPg;36}37 38void setUp(void){39 /* Initialize SQLite core and pcache each test */40 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_initialize());41 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3PcacheInitialize());42}43 44void tearDown(void){45 /* Shutdown pcache and SQLite core to avoid cross-test interference */46 sqlite3PcacheShutdown();47 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_shutdown());48}49 50#ifdef SQLITE_DEBUG51 52/* Basic: a newly fetched page is clean and sane */53void test_sqlite3PcachePageSanity_clean_page(void){54 PCache *pc = helperCreateCache(512);55 PgHdr *p1 = helperFetchPage(pc, 1);56 TEST_ASSERT_EQUAL_INT(1, sqlite3PcachePageSanity(p1));57 /* Cleanup */58 sqlite3PcacheMakeClean(p1); /* no-op but safe */59 sqlite3PcacheRelease(p1);60 helperDestroyCache(pc);61}62 63/* Single dirty page has correct list linkage and is sane */64void test_sqlite3PcachePageSanity_single_dirty(void){65 PCache *pc = helperCreateCache(512);66 PgHdr *p1 = helperFetchPage(pc, 1);67 sqlite3PcacheMakeDirty(p1);68 TEST_ASSERT_EQUAL_INT(1, sqlite3PcachePageSanity(p1));69 /* Cleanup */70 sqlite3PcacheMakeClean(p1);71 sqlite3PcacheRelease(p1);72 helperDestroyCache(pc);73}74 75/* Two dirty pages linked in LRU order remain sane */76void test_sqlite3PcachePageSanity_two_dirty_pages(void){77 PCache *pc = helperCreateCache(512);78 PgHdr *p1 = helperFetchPage(pc, 1);79 PgHdr *p2 = helperFetchPage(pc, 2);80 sqlite3PcacheMakeDirty(p1);81 sqlite3PcacheMakeDirty(p2);82 TEST_ASSERT_EQUAL_INT(1, sqlite3PcachePageSanity(p1));83 TEST_ASSERT_EQUAL_INT(1, sqlite3PcachePageSanity(p2));84 /* Cleanup */85 sqlite3PcacheMakeClean(p1);86 sqlite3PcacheMakeClean(p2);87 sqlite3PcacheRelease(p1);88 sqlite3PcacheRelease(p2);89 helperDestroyCache(pc);90}91 92/* Making a dirty page clean removes it from the dirty list; page stays sane */93void test_sqlite3PcachePageSanity_make_clean(void){94 PCache *pc = helperCreateCache(512);95 PgHdr *p1 = helperFetchPage(pc, 1);96 sqlite3PcacheMakeDirty(p1);97 sqlite3PcacheMakeClean(p1);98 TEST_ASSERT_EQUAL_INT(1, sqlite3PcachePageSanity(p1));99 /* Cleanup */100 sqlite3PcacheRelease(p1);101 helperDestroyCache(pc);102}103 104/* WRITEABLE implies DIRTY; sanity should pass if both are set */105void test_sqlite3PcachePageSanity_writeable_implies_dirty(void){106 PCache *pc = helperCreateCache(512);107 PgHdr *p1 = helperFetchPage(pc, 1);108 sqlite3PcacheMakeDirty(p1);109 p1->flags |= PGHDR_WRITEABLE; /* Valid combination: WRITEABLE implies DIRTY */110 TEST_ASSERT_EQUAL_INT(1, sqlite3PcachePageSanity(p1));111 /* Cleanup */112 sqlite3PcacheMakeClean(p1);113 sqlite3PcacheRelease(p1);114 helperDestroyCache(pc);115}116 117/* Releasing the last reference to a dirty page moves it to front of dirty list; page remains sane */118void test_sqlite3PcachePageSanity_release_moves_front_and_sane(void){119 PCache *pc = helperCreateCache(512);120 PgHdr *p1 = helperFetchPage(pc, 1);121 PgHdr *p2 = helperFetchPage(pc, 2);122 sqlite3PcacheMakeDirty(p1);123 sqlite3PcacheMakeDirty(p2);124 /* Add an extra ref to p2 and then release twice to trigger FRONT move on dirty list */125 sqlite3PcacheRef(p2);126 sqlite3PcacheRelease(p2);127 sqlite3PcacheRelease(p2); /* nRef now 0 but still dirty and on list */128 TEST_ASSERT_EQUAL_INT(1, sqlite3PcachePageSanity(p2));129 TEST_ASSERT_EQUAL_INT(1, sqlite3PcachePageSanity(p1));130 /* Cleanup: clean all and close */131 sqlite3PcacheCleanAll(pc);132 /* p1 had nRef=1; p2 had nRef=0. Release p1 */133 sqlite3PcacheRelease(p1);134 helperDestroyCache(pc);135}136 137/* Moving a dirty page with NEED_SYNC set stays sane after move */138void test_sqlite3PcachePageSanity_move_dirty_need_sync(void){139 PCache *pc = helperCreateCache(512);140 PgHdr *p3 = helperFetchPage(pc, 3);141 sqlite3PcacheMakeDirty(p3);142 p3->flags |= PGHDR_NEED_SYNC;143 sqlite3PcacheMove(p3, 5);144 TEST_ASSERT_EQUAL_INT(1, sqlite3PcachePageSanity(p3));145 /* Cleanup */146 sqlite3PcacheMakeClean(p3);147 sqlite3PcacheRelease(p3);148 helperDestroyCache(pc);149}150 151#else /* !SQLITE_DEBUG */152 153void test_sqlite3PcachePageSanity_unavailable_when_not_SQLITE_DEBUG(void){154 TEST_IGNORE_MESSAGE("sqlite3PcachePageSanity() is only available when SQLITE_DEBUG is defined");155}156 157#endif /* SQLITE_DEBUG */158 159int main(void){160 UNITY_BEGIN();161#ifdef SQLITE_DEBUG162 RUN_TEST(test_sqlite3PcachePageSanity_clean_page);163 RUN_TEST(test_sqlite3PcachePageSanity_single_dirty);164 RUN_TEST(test_sqlite3PcachePageSanity_two_dirty_pages);165 RUN_TEST(test_sqlite3PcachePageSanity_make_clean);166 RUN_TEST(test_sqlite3PcachePageSanity_writeable_implies_dirty);167 RUN_TEST(test_sqlite3PcachePageSanity_release_moves_front_and_sane);168 RUN_TEST(test_sqlite3PcachePageSanity_move_dirty_need_sync);169#else170 RUN_TEST(test_sqlite3PcachePageSanity_unavailable_when_not_SQLITE_DEBUG);171#endif172 return UNITY_END();173}