Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_pager_getPageNormal.c222 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdio.h>5#include <stdlib.h>6#include <string.h>7 8/* Prototype for the auto-generated test wrapper around static getPageNormal() */9int test_getPageNormal(Pager *pPager, Pgno pgno, DbPage **ppPage, int flags);10 11static int g_test_counter = 0;12 13static void make_temp_filename(char *zOut, int nOut){14  sqlite3_snprintf(nOut, zOut, "test_getPageNormal_%d.db", g_test_counter++);15}16 17static sqlite3* open_db_and_prepare(Btree **ppBtree, Pager **ppPager, int ensureData){18  int rc;19  sqlite3 *db = 0;20  char zFile[128];21 22  make_temp_filename(zFile, sizeof(zFile));23  rc = sqlite3_open(zFile, &db);24  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");25 26  /* Ensure journal mode is DELETE to keep readDbPage path simple */27  rc = sqlite3_exec(db, "PRAGMA journal_mode=DELETE;", 0, 0, 0);28  TEST_ASSERT(rc==SQLITE_OK || rc==SQLITE_DONE);29 30  if( ensureData ){31    /* Create some content to ensure dbSize >= 1 and file exists */32    rc = sqlite3_exec(db,33      "BEGIN;"34      "CREATE TABLE IF NOT EXISTS t(x);"35      "INSERT INTO t(x) VALUES(1);"36      "COMMIT;",37      0, 0, 038    );39    TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "Failed to create test table/row");40  }else{41    /* Touch the database to ensure Btree is initialized */42    rc = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS t0(y);", 0, 0, 0);43    TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);44  }45 46  /* Fetch internal Btree and Pager */47  TEST_ASSERT_NOT_NULL(db->aDb);48  TEST_ASSERT_NOT_NULL(db->aDb[0].pBt);49  *ppBtree = db->aDb[0].pBt;50  TEST_ASSERT_NOT_NULL((*ppBtree)->pBt);51  *ppPager = (*ppBtree)->pBt->pPager;52  TEST_ASSERT_NOT_NULL(*ppPager);53 54  /* Start a read transaction to satisfy pager asserts (eState>=PAGER_READER) */55  rc = sqlite3BtreeBeginTrans(*ppBtree, 0);56  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3BtreeBeginTrans failed");57 58  /* Ensure hasHeldSharedLock is set, as the code asserts this */59  (*ppPager)->hasHeldSharedLock = 1;60 61  return db;62}63 64static void close_db_and_cleanup(sqlite3 *db){65  /* End any transaction and close */66  /* If the Btree is still in a transaction, commit it. 67     Use sqlite3_exec for simplicity. */68  sqlite3_exec(db, "COMMIT;", 0, 0, 0);69  sqlite3_close(db);70}71 72void setUp(void) {73  /* no-op */74}75 76void tearDown(void) {77  /* no-op */78}79 80/* Test 1: pgno==0 should return SQLITE_CORRUPT and set *ppPage==NULL */81void test_getPageNormal_pgno_zero_returns_corrupt(void){82  Btree *pBtree = 0;83  Pager *pPager = 0;84  sqlite3 *db = open_db_and_prepare(&pBtree, &pPager, /*ensureData=*/1);85 86  DbPage *pPage = 0;87  int rc = test_getPageNormal(pPager, 0, &pPage, 0);88  TEST_ASSERT_EQUAL_INT(SQLITE_CORRUPT, rc);89  TEST_ASSERT_NULL(pPage);90 91  close_db_and_cleanup(db);92}93 94/* Test 2: PAGER_GET_NOCONTENT returns a zeroed page and success */95void test_getPageNormal_nocontent_zero_page(void){96  Btree *pBtree = 0;97  Pager *pPager = 0;98  sqlite3 *db = open_db_and_prepare(&pBtree, &pPager, /*ensureData=*/1);99 100  /* Choose a pgno beyond current dbSize to force the NOCONTENT/zero path.101     Also ensure pgno <= mxPgno to avoid SQLITE_FULL in this test. */102  Pgno pgno = (pPager->dbSize>0) ? pPager->dbSize + 1 : 2;103  if( pgno > pPager->mxPgno ){104    /* Expand limit slightly for test purposes */105    pPager->mxPgno = pgno + 10;106  }107 108  DbPage *pPage = 0;109  int rc = test_getPageNormal(pPager, pgno, &pPage, PAGER_GET_NOCONTENT);110  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);111  TEST_ASSERT_NOT_NULL(pPage);112  TEST_ASSERT_EQUAL_PTR(pPager, ((PgHdr*)pPage)->pPager);113  TEST_ASSERT_EQUAL_UINT32(pgno, ((PgHdr*)pPage)->pgno);114 115  /* Verify the page content is zeroed */116  unsigned char *p = (unsigned char *)((PgHdr*)pPage)->pData;117  int i;118  for(i=0; i<pPager->pageSize; i++){119    if( p[i]!=0 ){120      TEST_FAIL_MESSAGE("Page content not zeroed under PAGER_GET_NOCONTENT");121    }122  }123 124  sqlite3PagerUnref(pPage);125  close_db_and_cleanup(db);126}127 128/* Test 3: Cache hit when fetching a page already in cache increments hit stat */129void test_getPageNormal_cache_hit_increments_stat(void){130  Btree *pBtree = 0;131  Pager *pPager = 0;132  sqlite3 *db = open_db_and_prepare(&pBtree, &pPager, /*ensureData=*/1);133 134  /* Choose a pgno > dbSize; keep within mxPgno */135  Pgno pgno = (pPager->dbSize>0) ? pPager->dbSize + 1 : 2;136  if( pgno > pPager->mxPgno ){137    pPager->mxPgno = pgno + 10;138  }139 140  DbPage *pPage1 = 0;141  int rc = test_getPageNormal(pPager, pgno, &pPage1, PAGER_GET_NOCONTENT);142  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);143  TEST_ASSERT_NOT_NULL(pPage1);144 145  /* Second fetch without NOCONTENT should be a cache hit */146  int hitsBefore = pPager->aStat[PAGER_STAT_HIT];147  DbPage *pPage2 = 0;148  rc = test_getPageNormal(pPager, pgno, &pPage2, 0);149  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);150  TEST_ASSERT_NOT_NULL(pPage2);151  TEST_ASSERT_EQUAL_INT(hitsBefore + 1, pPager->aStat[PAGER_STAT_HIT]);152 153  /* Should be the same page object */154  TEST_ASSERT_EQUAL_PTR(pPage1, pPage2);155 156  sqlite3PagerUnref(pPage2);157  sqlite3PagerUnref(pPage1);158 159  close_db_and_cleanup(db);160}161 162/* Test 4: pgno > mxPgno -> SQLITE_FULL and *ppPage==NULL */163void test_getPageNormal_pgno_gt_mxPgno_returns_full(void){164  Btree *pBtree = 0;165  Pager *pPager = 0;166  sqlite3 *db = open_db_and_prepare(&pBtree, &pPager, /*ensureData=*/1);167 168  /* Force a low mxPgno and request a larger pgno */169  pPager->mxPgno = 5;170  Pgno pgno = 6;171 172  DbPage *pPage = 0;173  int rc = test_getPageNormal(pPager, pgno, &pPage, 0);174  TEST_ASSERT_EQUAL_INT(SQLITE_FULL, rc);175  TEST_ASSERT_NULL(pPage);176 177  close_db_and_cleanup(db);178}179 180/* Test 5: Reading an existing page without NOCONTENT reads from disk181   and increments miss/nRead counters. We also sanity check header signature. */182void test_getPageNormal_reads_from_disk_and_updates_stats(void){183  Btree *pBtree = 0;184  Pager *pPager = 0;185  sqlite3 *db = open_db_and_prepare(&pBtree, &pPager, /*ensureData=*/1);186 187  /* Make sure page 1 exists (table created in prepare ensures this) */188  Pgno pgno = 1;189 190  int missBefore = pPager->aStat[PAGER_STAT_MISS];191  int nReadBefore = pPager->nRead;192 193  DbPage *pPage = 0;194  int rc = test_getPageNormal(pPager, pgno, &pPage, 0);195  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);196  TEST_ASSERT_NOT_NULL(pPage);197 198  /* Miss and nRead should have incremented when a new page is read from disk */199  TEST_ASSERT_EQUAL_INT(missBefore + 1, pPager->aStat[PAGER_STAT_MISS]);200  TEST_ASSERT_EQUAL_INT(nReadBefore + 1, pPager->nRead);201 202  /* For page 1, expect SQLite database header "SQLite format 3\000" */203  if( ((PgHdr*)pPage)->pgno==1 ){204    const unsigned char *z = (const unsigned char *)((PgHdr*)pPage)->pData;205    /* Only perform this check if the database is not empty and page 1 was read206       into cache. It should be after creating a table. */207    TEST_ASSERT_EQUAL_MEMORY("SQLite format 3\000", z, 16);208  }209 210  sqlite3PagerUnref(pPage);211  close_db_and_cleanup(db);212}213 214int main(void){215  UNITY_BEGIN();216  RUN_TEST(test_getPageNormal_pgno_zero_returns_corrupt);217  RUN_TEST(test_getPageNormal_nocontent_zero_page);218  RUN_TEST(test_getPageNormal_cache_hit_increments_stat);219  RUN_TEST(test_getPageNormal_pgno_gt_mxPgno_returns_full);220  RUN_TEST(test_getPageNormal_reads_from_disk_and_updates_stats);221  return UNITY_END();222}