Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_pager_sqlite3PagerUnrefNotNull.c217 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Unity setup/teardown */7void setUp(void) {8  /* No global setup needed */9}10void tearDown(void) {11  /* No global teardown needed */12}13 14/* A small helper to open an in-memory database and extract its Pager */15static void open_memory_db_and_pager(sqlite3 **ppDb, Pager **ppPager){16  int rc;17  sqlite3 *db = 0;18  rc = sqlite3_open(":memory:", &db);19  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open(:memory:) failed");20  TEST_ASSERT_NOT_NULL(db);21 22  /* Access the main database Btree and underlying Pager */23  TEST_ASSERT_NOT_NULL(db->aDb);24  Btree *pBtree = db->aDb[0].pBt;25  TEST_ASSERT_NOT_NULL_MESSAGE(pBtree, "Main Btree is NULL");26  BtShared *pBtShared = pBtree->pBt;27  TEST_ASSERT_NOT_NULL_MESSAGE(pBtShared, "BtShared is NULL");28  Pager *pPager = pBtShared->pPager;29  TEST_ASSERT_NOT_NULL_MESSAGE(pPager, "Pager is NULL");30 31  *ppDb = db;32  *ppPager = pPager;33}34 35/* ---- Test infrastructure for simulating xUnfetch ---- */36 37typedef struct TestFile {38  sqlite3_file base;39  int nUnfetch;40  i64 lastOfst;41  void *lastP;42} TestFile;43 44static int tf_xUnfetch(sqlite3_file *pFile, i64 iOfst, void *pArg){45  TestFile *tf = (TestFile*)pFile;46  tf->nUnfetch++;47  tf->lastOfst = iOfst;48  tf->lastP = pArg;49  return SQLITE_OK;50}51 52/* sqlite3_io_methods for TestFile. Only xUnfetch is used here. */53static struct sqlite3_io_methods gTestIoMethods;54 55/* Initialize the test io-methods (idempotent) */56static void init_test_io_methods(void){57  memset(&gTestIoMethods, 0, sizeof(gTestIoMethods));58  gTestIoMethods.iVersion = 3;59  gTestIoMethods.xUnfetch = tf_xUnfetch;60}61 62/* ---- Tests ---- */63 64void test_sqlite3PagerUnrefNotNull_mmap_unfetch_and_freelist_empty(void){65  sqlite3 *db = 0;66  Pager *pPager = 0;67  open_memory_db_and_pager(&db, &pPager);68 69  /* Install our test sqlite3_file with iVersion>=3 and xUnfetch */70  init_test_io_methods();71  TestFile tf;72  memset(&tf, 0, sizeof(tf));73  tf.base.pMethods = &gTestIoMethods;74 75  sqlite3_file *origFd = pPager->fd;76  pPager->fd = &tf.base;77 78  /* Prepare a fake mapped page (PGHDR_MMAP) */79  PgHdr *pPg = (PgHdr*)sqlite3_malloc(sizeof(PgHdr));80  TEST_ASSERT_NOT_NULL(pPg);81  memset(pPg, 0, sizeof(PgHdr));82 83  /* Data buffer whose pointer should be passed to xUnfetch */84  void *pData = sqlite3_malloc(128);85  TEST_ASSERT_NOT_NULL(pData);86 87  pPg->pPager = pPager;88  pPg->flags = PGHDR_MMAP; /* Force mapped-page code path */89  pPg->pgno = 2;           /* Must not be 1, enforced by assert in helper */90  pPg->pData = pData;91 92  /* Start state: empty freelist, known nMmapOut value */93  PgHdr *oldFree = NULL;94  pPager->pMmapFreelist = oldFree;95  pPager->nMmapOut = 5;96 97  i64 expectedOfst = (i64)(pPg->pgno - 1) * (i64)pPager->pageSize;98 99  /* Call the function under test */100  sqlite3PagerUnrefNotNull((DbPage*)pPg);101 102  /* Verify xUnfetch called with correct args */103  TEST_ASSERT_EQUAL_INT(1, tf.nUnfetch);104  TEST_ASSERT_EQUAL_INT64(expectedOfst, tf.lastOfst);105  TEST_ASSERT_EQUAL_PTR(pData, tf.lastP);106 107  /* Verify freelist push and nMmapOut decrement */108  TEST_ASSERT_EQUAL_PTR(pPg, pPager->pMmapFreelist);109  TEST_ASSERT_EQUAL_PTR(oldFree, pPg->pDirty); /* pDirty points to old freelist head */110  TEST_ASSERT_EQUAL_INT(4, pPager->nMmapOut);111 112  /* Restore pager fd before closing the database */113  pPager->fd = origFd;114 115  /* Cleanup our allocations and detach our fake page from freelist */116  pPager->pMmapFreelist = oldFree; /* remove our injected head safely */117  sqlite3_free(pPg);118  sqlite3_free(pData);119 120  sqlite3_close(db);121}122 123void test_sqlite3PagerUnrefNotNull_mmap_unfetch_and_freelist_nonempty(void){124  sqlite3 *db = 0;125  Pager *pPager = 0;126  open_memory_db_and_pager(&db, &pPager);127 128  init_test_io_methods();129  TestFile tf;130  memset(&tf, 0, sizeof(tf));131  tf.base.pMethods = &gTestIoMethods;132 133  sqlite3_file *origFd = pPager->fd;134  pPager->fd = &tf.base;135 136  /* Existing freelist head */137  PgHdr *existing = (PgHdr*)sqlite3_malloc(sizeof(PgHdr));138  TEST_ASSERT_NOT_NULL(existing);139  memset(existing, 0, sizeof(PgHdr));140 141  pPager->pMmapFreelist = existing;142  pPager->nMmapOut = 2;143 144  /* New page to unref (mapped) */145  PgHdr *pPg = (PgHdr*)sqlite3_malloc(sizeof(PgHdr));146  TEST_ASSERT_NOT_NULL(pPg);147  memset(pPg, 0, sizeof(PgHdr));148 149  void *pData = sqlite3_malloc(64);150  TEST_ASSERT_NOT_NULL(pData);151 152  pPg->pPager = pPager;153  pPg->flags = PGHDR_MMAP;154  pPg->pgno = 3;155  pPg->pData = pData;156 157  i64 expectedOfst = (i64)(pPg->pgno - 1) * (i64)pPager->pageSize;158 159  sqlite3PagerUnrefNotNull((DbPage*)pPg);160 161  /* Verify xUnfetch called and freelist chain updated */162  TEST_ASSERT_EQUAL_INT(1, tf.nUnfetch);163  TEST_ASSERT_EQUAL_INT64(expectedOfst, tf.lastOfst);164  TEST_ASSERT_EQUAL_PTR(pData, tf.lastP);165 166  TEST_ASSERT_EQUAL_PTR(pPg, pPager->pMmapFreelist);167  TEST_ASSERT_EQUAL_PTR(existing, pPg->pDirty);168  TEST_ASSERT_EQUAL_INT(1, pPager->nMmapOut);169 170  /* Restore fd and cleanup */171  pPager->fd = origFd;172 173  /* Detach our injected node; keep original freelist head */174  pPager->pMmapFreelist = existing;175 176  sqlite3_free(pPg);177  sqlite3_free(existing);178  sqlite3_free(pData);179 180  sqlite3_close(db);181}182 183void test_sqlite3PagerUnrefNotNull_non_mmap_reduces_refcount(void){184  sqlite3 *db = 0;185  Pager *pPager = 0;186  open_memory_db_and_pager(&db, &pPager);187 188  /* Fetch a real page via pager to obtain a referenced DbPage.189     Use page 2 (not page 1) so it's safe to unref here. */190  DbPage *pPage2 = 0;191  int rc = sqlite3PagerGet(pPager, 2, &pPage2, 0);192  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3PagerGet failed");193  TEST_ASSERT_NOT_NULL(pPage2);194 195  int before = sqlite3PcacheRefCount(pPager->pPCache);196 197  /* Ensure the page is not flagged as mmap (typical for :memory:) */198  /* We don't assert on flags, but we rely on natural behavior: non-mmap path. */199 200  sqlite3PagerUnrefNotNull(pPage2);201 202  int after = sqlite3PcacheRefCount(pPager->pPCache);203 204  TEST_ASSERT_EQUAL_INT_MESSAGE(before - 1, after,205    "Refcount should decrease by exactly 1 after unref (non-mmap)");206 207  sqlite3_close(db);208}209 210/* Unity main */211int main(void){212  UNITY_BEGIN();213  RUN_TEST(test_sqlite3PagerUnrefNotNull_mmap_unfetch_and_freelist_empty);214  RUN_TEST(test_sqlite3PagerUnrefNotNull_mmap_unfetch_and_freelist_nonempty);215  RUN_TEST(test_sqlite3PagerUnrefNotNull_non_mmap_reduces_refcount);216  return UNITY_END();217}