Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_pager_zeroJournalHdr.c306 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#include <sys/stat.h>8#include <errno.h>9 10#ifdef _WIN3211#include <io.h>12#define unlink _unlink13#else14#include <unistd.h>15#endif16 17/* Prototype for the auto-generated wrapper around the static function */18extern int test_zeroJournalHdr(Pager *pPager, int doTruncate);19 20/* Helpers */21 22static int exec_sql(sqlite3 *db, const char *sql){23  return sqlite3_exec(db, sql, 0, 0, 0);24}25 26static sqlite3* open_db(const char *path){27  sqlite3 *db = NULL;28  int rc = sqlite3_open(path, &db);29  if( rc!=SQLITE_OK ){30    /* Fail fast in tests if DB can't be opened */31    return NULL;32  }33  return db;34}35 36static void close_db(sqlite3 *db){37  if( db ){38    sqlite3_close(db);39  }40}41 42static int file_exists(const char *path){43  struct stat st;44  return stat(path, &st)==0;45}46 47static sqlite3_int64 file_size(const char *path){48  struct stat st;49  if( stat(path, &st)!=0 ) return -1;50#ifdef _WIN3251  return (sqlite3_int64)st.st_size;52#else53  return (sqlite3_int64)st.st_size;54#endif55}56 57static int read_bytes(const char *path, void *buf, size_t n){58  FILE *f = fopen(path, "rb");59  if( !f ) return -1;60  size_t got = fread(buf, 1, n, f);61  fclose(f);62  return (int)got;63}64 65static void build_journal_path(sqlite3 *db, char *out, size_t nOut){66  const char *dbfile = sqlite3_db_filename(db, "main");67  TEST_ASSERT_NOT_NULL_MESSAGE(dbfile, "Database filename is NULL");68  TEST_ASSERT_TRUE_MESSAGE(strlen(dbfile)+9 < nOut, "Journal path buffer too small");69  strcpy(out, dbfile);70  strcat(out, "-journal");71}72 73/* Create a write transaction that definitely creates a rollback journal.74   For the first creation, set a page size to ensure larger journal when needed. */75static void begin_write_with_data(sqlite3 *db, int ensureLarge){76  int rc;77 78  /* Ensure rollback journal (not WAL) and persistence of journal file */79  rc = exec_sql(db, "PRAGMA journal_mode=PERSIST;");80  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);81 82  /* Optionally set page size big enough to ensure large journal content */83  if( ensureLarge ){84    /* Set before any objects are created to take effect */85    rc = exec_sql(db, "PRAGMA page_size=4096;");86    TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);87  }88 89  rc = exec_sql(db, "BEGIN IMMEDIATE;");90  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);91 92  /* Create table if not exists and insert some data to force page writes */93  rc = exec_sql(db, "CREATE TABLE IF NOT EXISTS t(a);");94  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);95 96  /* Insert multiple rows to ensure journal grows */97  rc = exec_sql(db, "INSERT INTO t VALUES (randomblob(1000));"98                     "INSERT INTO t VALUES (randomblob(1000));"99                     "INSERT INTO t VALUES (randomblob(1000));");100  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);101}102 103static void commit_and_cleanup(sqlite3 *db){104  int rc = exec_sql(db, "COMMIT;");105  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);106}107 108/* Global per-test setup/teardown */109void setUp(void) {110  /* No-op */111}112void tearDown(void) {113  /* No-op */114}115 116/* Utility to create a unique db path per test */117static void make_db_path(char *out, size_t n, const char *suffix){118  snprintf(out, n, "test_zerojournalhdr_%s.db", suffix);119}120 121/* Test 1: doTruncate=1 should truncate the journal file to 0 bytes */122void test_zeroJournalHdr_truncate_to_zero(void){123  char dbpath[256];124  char jpath[512];125  make_db_path(dbpath, sizeof(dbpath), "truncate");126  unlink(dbpath);127  unlink("test_zerojournalhdr_truncate.db-journal");128 129  sqlite3 *db = open_db(dbpath);130  TEST_ASSERT_NOT_NULL(db);131 132  begin_write_with_data(db, 0);133 134  build_journal_path(db, jpath, sizeof(jpath));135  TEST_ASSERT_TRUE_MESSAGE(file_exists(jpath), "Journal file does not exist after write");136  sqlite3_int64 before = file_size(jpath);137  TEST_ASSERT_TRUE_MESSAGE(before > 0, "Journal file size not greater than 0 before zeroJournalHdr");138 139  /* Get Pager* from Btree */140  TEST_ASSERT_NOT_NULL(db->aDb);141  TEST_ASSERT_NOT_NULL(db->aDb[0].pBt);142  Pager *pPager = sqlite3BtreePager(db->aDb[0].pBt);143  TEST_ASSERT_NOT_NULL(pPager);144 145  int rc = test_zeroJournalHdr(pPager, 1);146  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);147 148  sqlite3_int64 after = file_size(jpath);149  TEST_ASSERT_EQUAL_INT64(0, after);150 151  commit_and_cleanup(db);152  close_db(db);153 154  unlink(dbpath);155  unlink(jpath);156}157 158/* Test 2: doTruncate=0 with default journal_size_limit (-1) zeroes 28-byte header, size unchanged */159void test_zeroJournalHdr_zero_header_maintains_size(void){160  char dbpath[256];161  char jpath[512];162  make_db_path(dbpath, sizeof(dbpath), "zerohdr");163  unlink(dbpath);164  unlink("test_zerojournalhdr_zerohdr.db-journal");165 166  sqlite3 *db = open_db(dbpath);167  TEST_ASSERT_NOT_NULL(db);168 169  begin_write_with_data(db, 0);170 171  build_journal_path(db, jpath, sizeof(jpath));172  TEST_ASSERT_TRUE_MESSAGE(file_exists(jpath), "Journal file does not exist after write");173  sqlite3_int64 sz_before = file_size(jpath);174  TEST_ASSERT_TRUE_MESSAGE(sz_before > 28, "Journal file too small before zeroJournalHdr");175 176  TEST_ASSERT_NOT_NULL(db->aDb);177  TEST_ASSERT_NOT_NULL(db->aDb[0].pBt);178  Pager *pPager = sqlite3BtreePager(db->aDb[0].pBt);179  TEST_ASSERT_NOT_NULL(pPager);180 181  int rc = test_zeroJournalHdr(pPager, 0);182  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);183 184  sqlite3_int64 sz_after = file_size(jpath);185  TEST_ASSERT_EQUAL_INT64(sz_before, sz_after);186 187  unsigned char hdr[28];188  int got = read_bytes(jpath, hdr, sizeof(hdr));189  TEST_ASSERT_EQUAL_INT(28, got);190  for(int i=0;i<28;i++){191    if( hdr[i]!=0 ){192      TEST_FAIL_MESSAGE("Journal header not zeroed");193    }194  }195 196  commit_and_cleanup(db);197  close_db(db);198 199  unlink(dbpath);200  unlink(jpath);201}202 203/* Test 3: doTruncate=0 with journal_size_limit=0 should truncate to 0 */204void test_zeroJournalHdr_limit_zero_truncates(void){205  char dbpath[256];206  char jpath[512];207  make_db_path(dbpath, sizeof(dbpath), "limit0");208  unlink(dbpath);209  unlink("test_zerojournalhdr_limit0.db-journal");210 211  sqlite3 *db = open_db(dbpath);212  TEST_ASSERT_NOT_NULL(db);213 214  /* Set journal mode and limit before write */215  int rc = exec_sql(db, "PRAGMA journal_mode=PERSIST;");216  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);217  rc = exec_sql(db, "PRAGMA journal_size_limit=0;");218  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);219 220  rc = exec_sql(db, "BEGIN IMMEDIATE;");221  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);222  rc = exec_sql(db, "CREATE TABLE IF NOT EXISTS t(a); INSERT INTO t VALUES(1);");223  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);224 225  build_journal_path(db, jpath, sizeof(jpath));226  TEST_ASSERT_TRUE_MESSAGE(file_exists(jpath), "Journal file does not exist after write");227 228  TEST_ASSERT_NOT_NULL(db->aDb);229  TEST_ASSERT_NOT_NULL(db->aDb[0].pBt);230  Pager *pPager = sqlite3BtreePager(db->aDb[0].pBt);231  TEST_ASSERT_NOT_NULL(pPager);232 233  rc = test_zeroJournalHdr(pPager, 0);234  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);235 236  sqlite3_int64 after = file_size(jpath);237  TEST_ASSERT_EQUAL_INT64(0, after);238 239  commit_and_cleanup(db);240  close_db(db);241 242  unlink(dbpath);243  unlink(jpath);244}245 246/* Test 4: doTruncate=0 with positive journal_size_limit truncates to the limit when larger */247void test_zeroJournalHdr_truncate_to_limit(void){248  char dbpath[256];249  char jpath[512];250  make_db_path(dbpath, sizeof(dbpath), "limit1024");251  unlink(dbpath);252  unlink("test_zerojournalhdr_limit1024.db-journal");253 254  sqlite3 *db = open_db(dbpath);255  TEST_ASSERT_NOT_NULL(db);256 257  /* Set journal mode and page size to grow journal, and set small size limit */258  int rc = exec_sql(db, "PRAGMA journal_mode=PERSIST;");259  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);260  rc = exec_sql(db, "PRAGMA journal_size_limit=1024;");261  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);262 263  begin_write_with_data(db, 1); /* ensureLarge=1 to set page_size=4096 */264 265  build_journal_path(db, jpath, sizeof(jpath));266  TEST_ASSERT_TRUE_MESSAGE(file_exists(jpath), "Journal file does not exist after write");267 268  sqlite3_int64 before = file_size(jpath);269  TEST_ASSERT_TRUE_MESSAGE(before > 2048, "Journal file unexpectedly small before zeroJournalHdr");270 271  TEST_ASSERT_NOT_NULL(db->aDb);272  TEST_ASSERT_NOT_NULL(db->aDb[0].pBt);273  Pager *pPager = sqlite3BtreePager(db->aDb[0].pBt);274  TEST_ASSERT_NOT_NULL(pPager);275 276  rc = test_zeroJournalHdr(pPager, 0);277  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);278 279  sqlite3_int64 after = file_size(jpath);280  TEST_ASSERT_EQUAL_INT64(1024, after);281 282  /* Verify first 28 bytes are zeroed after the call and truncation */283  unsigned char hdr[28];284  int got = read_bytes(jpath, hdr, sizeof(hdr));285  TEST_ASSERT_EQUAL_INT(28, got);286  for(int i=0;i<28;i++){287    if( hdr[i]!=0 ){288      TEST_FAIL_MESSAGE("Journal header not zeroed after truncate-to-limit");289    }290  }291 292  commit_and_cleanup(db);293  close_db(db);294 295  unlink(dbpath);296  unlink(jpath);297}298 299int main(void){300  UNITY_BEGIN();301  RUN_TEST(test_zeroJournalHdr_truncate_to_zero);302  RUN_TEST(test_zeroJournalHdr_zero_header_maintains_size);303  RUN_TEST(test_zeroJournalHdr_limit_zero_truncates);304  RUN_TEST(test_zeroJournalHdr_truncate_to_limit);305  return UNITY_END();306}