Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_pager_writeJournalHdr.c367 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Forward declaration of the test wrapper for the static function */7int test_writeJournalHdr(Pager *pPager);8 9/* A simple in-memory sqlite3_file to capture writes from writeJournalHdr */10typedef struct TestMemFile TestMemFile;11struct TestMemFile {12  sqlite3_file base;              /* Must be first */13  unsigned char *data;14  sqlite3_int64 sz;15  sqlite3_int64 cap;16  int devchar;                    /* Device characteristics to report */17  int write_count;                /* Count writes for verification */18};19 20static void memfileEnsureCap(TestMemFile *p, sqlite3_int64 newCap){21  if( newCap <= p->cap ) return;22  sqlite3_int64 ncap = p->cap ? p->cap : 1024;23  while( ncap < newCap ) ncap *= 2;24  unsigned char *nd = (unsigned char*)sqlite3_realloc(p->data, (int)ncap);25  if( nd==0 ){26    /* OOM shouldn't happen in tests; if it does, keep old buffer to avoid UB */27    return;28  }29  if( ncap > p->cap ){30    memset(nd + p->cap, 0, (size_t)(ncap - p->cap));31  }32  p->data = nd;33  p->cap = ncap;34}35 36static int memClose(sqlite3_file *pFile){37  TestMemFile *p = (TestMemFile*)pFile;38  if( p->data ) sqlite3_free(p->data);39  p->data = 0;40  p->sz = 0;41  p->cap = 0;42  p->devchar = 0;43  p->write_count = 0;44  p->base.pMethods = 0;45  return SQLITE_OK;46}47static int memRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite3_int64 iOfst){48  TestMemFile *p = (TestMemFile*)pFile;49  if( iOfst + iAmt > p->sz ){50    /* As per VFS contract, read beyond EOF returns SQLITE_IOERR_SHORT_READ51       but also fills available bytes and zero-fills the rest. For tests,52       just zero-fill fully. */53    memset(zBuf, 0, iAmt);54    return SQLITE_OK;55  }56  memcpy(zBuf, p->data + iOfst, (size_t)iAmt);57  return SQLITE_OK;58}59static int memWrite(sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite3_int64 iOfst){60  TestMemFile *p = (TestMemFile*)pFile;61  sqlite3_int64 end = iOfst + iAmt;62  memfileEnsureCap(p, end);63  if( iOfst > p->sz ){64    memset(p->data + p->sz, 0, (size_t)(iOfst - p->sz));65  }66  memcpy(p->data + iOfst, zBuf, (size_t)iAmt);67  if( end > p->sz ) p->sz = end;68  p->write_count++;69  return SQLITE_OK;70}71static int memTruncate(sqlite3_file *pFile, sqlite3_int64 size){72  TestMemFile *p = (TestMemFile*)pFile;73  if( size < p->sz ){74    p->sz = size;75  }else if( size > p->sz ){76    memfileEnsureCap(p, size);77    memset(p->data + p->sz, 0, (size_t)(size - p->sz));78    p->sz = size;79  }80  return SQLITE_OK;81}82static int memSync(sqlite3_file *pFile, int flags){83  (void)pFile; (void)flags;84  return SQLITE_OK;85}86static int memFileSize(sqlite3_file *pFile, sqlite3_int64 *pSize){87  TestMemFile *p = (TestMemFile*)pFile;88  *pSize = p->sz;89  return SQLITE_OK;90}91static int memLock(sqlite3_file *pFile, int eLock){ (void)pFile; (void)eLock; return SQLITE_OK; }92static int memUnlock(sqlite3_file *pFile, int eLock){ (void)pFile; (void)eLock; return SQLITE_OK; }93static int memCheckReservedLock(sqlite3_file *pFile, int *pResOut){ (void)pFile; *pResOut = 0; return SQLITE_OK; }94static int memFileControl(sqlite3_file *pFile, int op, void *pArg){ (void)pFile; (void)op; (void)pArg; return SQLITE_NOTFOUND; }95static int memSectorSize(sqlite3_file *pFile){ (void)pFile; return 512; }96static int memDeviceCharacteristics(sqlite3_file *pFile){97  TestMemFile *p = (TestMemFile*)pFile;98  return p->devchar;99}100 101static const sqlite3_io_methods TestMemFileMethods = {102  1,                        /* iVersion */103  memClose,104  memRead,105  memWrite,106  memTruncate,107  memSync,108  memFileSize,109  memLock,110  memUnlock,111  memCheckReservedLock,112  memFileControl,113  memSectorSize,114  memDeviceCharacteristics115};116 117/* Helper to initialize a TestMemFile (open file) */118static void memfileInit(TestMemFile *p, int devchar){119  memset(p, 0, sizeof(*p));120  p->base.pMethods = &TestMemFileMethods;121  p->devchar = devchar;122  p->data = 0;123  p->sz = 0;124  p->cap = 0;125  p->write_count = 0;126}127 128/* Unity hooks */129void setUp(void) { }130void tearDown(void) { }131 132/* Utility to allocate and zero a Pager */133static Pager *allocZeroPager(void){134  Pager *p = (Pager*)sqlite3_malloc((int)sizeof(Pager));135  TEST_ASSERT_NOT_NULL(p);136  memset(p, 0, sizeof(Pager));137  return p;138}139 140/* Read big-endian 32-bit from buffer using SQLite macro */141static u32 be32_at(const unsigned char *p){142  return get4byte((u8*)p);143}144 145/* Test 1: Basic header write at offset 0, noSync=1 path */146void test_writeJournalHdr_basic_zero_offset(void){147  Pager *p = allocZeroPager();148 149  /* Set up journal file (jfd) */150  TestMemFile jfd;151  memfileInit(&jfd, 0);152 153  /* Pager fields */154  p->jfd = &jfd.base;155  p->fd = 0; /* NULL - allowed because noSync=1 */156  p->noSync = 1;               /* Triggers 0xFFFFFFFF in nRec and short-circuits fd usage */157  p->journalMode = 0;          /* Not MEMORY */158  p->journalOff = 0;           /* Start at 0 */159  p->dbOrigSize = 12345;160  p->sectorSize = 512;161  p->pageSize = 1024;162 163  p->pTmpSpace = (char*)sqlite3_malloc((int)p->pageSize);164  TEST_ASSERT_NOT_NULL(p->pTmpSpace);165 166  int rc = test_writeJournalHdr(p);167  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);168 169  /* Verify offsets */170  TEST_ASSERT_EQUAL_INT64(0, p->journalHdr);171  TEST_ASSERT_EQUAL_INT64(512, p->journalOff);172  TEST_ASSERT_EQUAL_INT64(512, jfd.sz);173 174  /* Verify header fields at offset 0 */175  const unsigned char *hdr = jfd.data;176  /* nRec field should be 0xFFFFFFFF when noSync=1 */177  TEST_ASSERT_EQUAL_UINT32(0xFFFFFFFFu, be32_at(hdr + 8));178  /* dbOrigSize, sectorSize, pageSize */179  TEST_ASSERT_EQUAL_UINT32(p->dbOrigSize, be32_at(hdr + 16));180  TEST_ASSERT_EQUAL_UINT32(p->sectorSize, be32_at(hdr + 20));181  TEST_ASSERT_EQUAL_UINT32(p->pageSize,  be32_at(hdr + 24));182 183  sqlite3_free(p->pTmpSpace);184  sqlite3_free(p);185  memClose(&jfd.base);186}187 188/* Test 2: Alignment from non-zero journalOff and savepoint update */189void test_writeJournalHdr_alignment_and_savepoint(void){190  Pager *p = allocZeroPager();191 192  TestMemFile jfd;193  memfileInit(&jfd, 0);194 195  p->jfd = &jfd.base;196  p->fd = 0;197  p->noSync = 1;198  p->journalMode = 0;199  p->journalOff = 100;         /* Unaligned - should align up to 512 */200  p->dbOrigSize = 7;201  p->sectorSize = 512;202  p->pageSize = 1024;203 204  /* Savepoints: first has iHdrOffset==0 -> should become old journalOff (100).205     Second already set -> unchanged. */206  p->nSavepoint = 2;207  p->aSavepoint = (PagerSavepoint*)sqlite3_malloc(sizeof(PagerSavepoint)*2);208  TEST_ASSERT_NOT_NULL(p->aSavepoint);209  memset(p->aSavepoint, 0, sizeof(PagerSavepoint)*2);210  p->aSavepoint[0].iHdrOffset = 0;211  p->aSavepoint[1].iHdrOffset = 123;212 213  p->pTmpSpace = (char*)sqlite3_malloc((int)p->pageSize);214  TEST_ASSERT_NOT_NULL(p->pTmpSpace);215 216  int rc = test_writeJournalHdr(p);217  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);218 219  TEST_ASSERT_EQUAL_INT64(512, p->journalHdr);220  TEST_ASSERT_EQUAL_INT64(1024, p->journalOff);221  TEST_ASSERT_EQUAL_INT64(1024, jfd.sz);222 223  /* Savepoint expectations */224  TEST_ASSERT_EQUAL_INT64(100, p->aSavepoint[0].iHdrOffset);225  TEST_ASSERT_EQUAL_INT64(123, p->aSavepoint[1].iHdrOffset);226 227  /* Verify header fields at offset 512 */228  const unsigned char *hdr = jfd.data + 512;229  TEST_ASSERT_EQUAL_UINT32(0xFFFFFFFFu, be32_at(hdr + 8));230  TEST_ASSERT_EQUAL_UINT32(p->dbOrigSize, be32_at(hdr + 16));231  TEST_ASSERT_EQUAL_UINT32(p->sectorSize, be32_at(hdr + 20));232  TEST_ASSERT_EQUAL_UINT32(p->pageSize,  be32_at(hdr + 24));233 234  sqlite3_free(p->aSavepoint);235  sqlite3_free(p->pTmpSpace);236  sqlite3_free(p);237  memClose(&jfd.base);238}239 240/* Test 3: Multiple writes when pageSize < sectorSize */241void test_writeJournalHdr_multiple_writes_when_pagesize_lt_sector(void){242  Pager *p = allocZeroPager();243 244  TestMemFile jfd;245  memfileInit(&jfd, 0);246 247  p->jfd = &jfd.base;248  p->fd = 0;249  p->noSync = 1;250  p->journalMode = 0;251  p->journalOff = 0;252  p->dbOrigSize = 999;253  p->sectorSize = 512;   /* Header sector */254  p->pageSize = 256;     /* Smaller than sector -> expects 2 writes of 256 */255 256  p->pTmpSpace = (char*)sqlite3_malloc((int)p->pageSize);257  TEST_ASSERT_NOT_NULL(p->pTmpSpace);258 259  int rc = test_writeJournalHdr(p);260  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);261 262  TEST_ASSERT_EQUAL_INT64(0, p->journalHdr);263  TEST_ASSERT_EQUAL_INT64(512, p->journalOff);264  TEST_ASSERT_EQUAL_INT64(512, jfd.sz);265  TEST_ASSERT_EQUAL_INT(2, jfd.write_count);266 267  const unsigned char *hdr = jfd.data;268  TEST_ASSERT_EQUAL_UINT32(0xFFFFFFFFu, be32_at(hdr + 8));269  TEST_ASSERT_EQUAL_UINT32(p->dbOrigSize, be32_at(hdr + 16));270  TEST_ASSERT_EQUAL_UINT32(p->sectorSize, be32_at(hdr + 20));271  TEST_ASSERT_EQUAL_UINT32(p->pageSize,  be32_at(hdr + 24));272 273  sqlite3_free(p->pTmpSpace);274  sqlite3_free(p);275  memClose(&jfd.base);276}277 278/* Test 4: SAFE_APPEND path (noSync=0, fd has SAFE_APPEND) -> nRec=0xFFFFFFFF */279void test_writeJournalHdr_safe_append_sets_nRec_FFFFFFFF(void){280  Pager *p = allocZeroPager();281 282  TestMemFile jfd, fd;283  memfileInit(&jfd, 0);284 285  /* fd device with SAFE_APPEND characteristic */286  memfileInit(&fd, SQLITE_IOCAP_SAFE_APPEND);287 288  p->jfd = &jfd.base;289  p->fd = &fd.base;290  p->noSync = 0;               /* Must be 0 to test SAFE_APPEND branch */291  p->journalMode = 0;          /* Not MEMORY */292  p->journalOff = 0;293  p->dbOrigSize = 42;294  p->sectorSize = 512;295  p->pageSize = 4096;296 297  p->pTmpSpace = (char*)sqlite3_malloc((int)p->pageSize);298  TEST_ASSERT_NOT_NULL(p->pTmpSpace);299 300  int rc = test_writeJournalHdr(p);301  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);302 303  TEST_ASSERT_EQUAL_INT64(0, p->journalHdr);304  TEST_ASSERT_EQUAL_INT64(512, p->journalOff);305  TEST_ASSERT_EQUAL_INT64(512, jfd.sz);306 307  const unsigned char *hdr = jfd.data;308  TEST_ASSERT_EQUAL_UINT32(0xFFFFFFFFu, be32_at(hdr + 8));309  TEST_ASSERT_EQUAL_UINT32(p->dbOrigSize, be32_at(hdr + 16));310  TEST_ASSERT_EQUAL_UINT32(p->sectorSize, be32_at(hdr + 20));311  TEST_ASSERT_EQUAL_UINT32(p->pageSize,  be32_at(hdr + 24));312 313  sqlite3_free(p->pTmpSpace);314  sqlite3_free(p);315  memClose(&jfd.base);316  memClose(&fd.base);317}318 319/* Test 5: Non-safe path (noSync=0, fd has no SAFE_APPEND) -> nRec==0 */320void test_writeJournalHdr_no_safe_append_sets_nRec_zero(void){321  Pager *p = allocZeroPager();322 323  TestMemFile jfd, fd;324  memfileInit(&jfd, 0);325  memfileInit(&fd, 0);   /* No special device characteristics */326 327  p->jfd = &jfd.base;328  p->fd = &fd.base;329  p->noSync = 0;330  p->journalMode = 0;    /* Not MEMORY */331  p->journalOff = 0;332  p->dbOrigSize = 31415;333  p->sectorSize = 512;334  p->pageSize = 2048;335 336  p->pTmpSpace = (char*)sqlite3_malloc((int)p->pageSize);337  TEST_ASSERT_NOT_NULL(p->pTmpSpace);338 339  int rc = test_writeJournalHdr(p);340  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);341 342  TEST_ASSERT_EQUAL_INT64(0, p->journalHdr);343  TEST_ASSERT_EQUAL_INT64(512, p->journalOff);344  TEST_ASSERT_EQUAL_INT64(512, jfd.sz);345 346  const unsigned char *hdr = jfd.data;347  /* In this branch, first 12 bytes were zeroed; nRec at +8 is 0. */348  TEST_ASSERT_EQUAL_UINT32(0u, be32_at(hdr + 8));349  TEST_ASSERT_EQUAL_UINT32(p->dbOrigSize, be32_at(hdr + 16));350  TEST_ASSERT_EQUAL_UINT32(p->sectorSize, be32_at(hdr + 20));351  TEST_ASSERT_EQUAL_UINT32(p->pageSize,  be32_at(hdr + 24));352 353  sqlite3_free(p->pTmpSpace);354  sqlite3_free(p);355  memClose(&jfd.base);356  memClose(&fd.base);357}358 359int main(void){360  UNITY_BEGIN();361  RUN_TEST(test_writeJournalHdr_basic_zero_offset);362  RUN_TEST(test_writeJournalHdr_alignment_and_savepoint);363  RUN_TEST(test_writeJournalHdr_multiple_writes_when_pagesize_lt_sector);364  RUN_TEST(test_writeJournalHdr_safe_append_sets_nRec_FFFFFFFF);365  RUN_TEST(test_writeJournalHdr_no_safe_append_sets_nRec_zero);366  return UNITY_END();367}