AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <stdio.h>5#include <string.h>6#include <time.h>7 8/* Helper: create a unique temporary filename in the current directory */9static void makeTempDbPath(char *buf, size_t buflen, const char *tag){10 static unsigned counter = 0;11 unsigned rnd = (unsigned)time(NULL) ^ (unsigned)(uintptr_t)&buf ^ counter++;12 sqlite3_snprintf((int)buflen, buf, "test_pager_close_%s_%u.db", tag ? tag : "x", rnd);13}14 15/* Helper: delete possible database-related files */16static void cleanupDbFiles(const char *zDb){17 char zJournal[1024];18 char zWal[1024];19 char zShm[1024];20 sqlite3_snprintf((int)sizeof(zJournal), zJournal, "%s-journal", zDb);21 sqlite3_snprintf((int)sizeof(zWal), zWal, "%s-wal", zDb);22 sqlite3_snprintf((int)sizeof(zShm), zShm, "%s-shm", zDb);23 remove(zJournal);24 remove(zWal);25 remove(zShm);26 remove(zDb);27}28 29/* Helper: open a Pager on the provided filename */30static Pager* openPagerOnFile(const char *zDbPath){31 sqlite3_vfs *pVfs = sqlite3_vfs_find(0);32 TEST_ASSERT_NOT_NULL_MESSAGE(pVfs, "No default VFS found");33 34 Pager *pPager = 0;35 /* Use common vfsFlags for a main db file that can be created. */36 int vfsFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB;37 /* nExtra=0, flags=0 (defaults), fd=NULL (pager opens file itself), xReinit=NULL */38 int rc = sqlite3PagerOpen(pVfs, 0, &pPager, zDbPath, 0, 0, vfsFlags, 0);39 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3PagerOpen failed");40 TEST_ASSERT_NOT_NULL(pPager);41 return pPager;42}43 44/* Helper: verify we can open the file via the public API and run a simple query */45static void assertDbOpensAndSelect1(const char *zDbPath){46 sqlite3 *db = 0;47 int rc = sqlite3_open(zDbPath, &db);48 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");49 rc = sqlite3_exec(db, "SELECT 1;", 0, 0, 0);50 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_exec SELECT 1 failed");51 sqlite3_close(db);52}53 54void setUp(void) {55 sqlite3_initialize();56}57 58void tearDown(void) {59 /* No global shutdown here to avoid interfering with other tests */60}61 62/* Test: Close a freshly opened pager (no transaction/journal). */63void test_sqlite3PagerClose_basic(void){64 char zDb[512];65 makeTempDbPath(zDb, sizeof(zDb), "basic");66 cleanupDbFiles(zDb);67 68 Pager *pPager = openPagerOnFile(zDb);69 70 int rc = sqlite3PagerClose(pPager, NULL);71 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);72 73 /* After close, database should be openable and usable */74 assertDbOpensAndSelect1(zDb);75 76 cleanupDbFiles(zDb);77}78 79/* Test: Begin a write (dirty a page to force journal open), then close the pager. */80void test_sqlite3PagerClose_with_dirty_page(void){81 char zDb[512];82 makeTempDbPath(zDb, sizeof(zDb), "dirty");83 cleanupDbFiles(zDb);84 85 Pager *pPager = openPagerOnFile(zDb);86 87 /* Fetch page 1 and mark it dirty to ensure a journal is opened. */88 DbPage *pPg = 0;89 int rc = sqlite3PagerGet(pPager, 1, &pPg, 0);90 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3PagerGet failed");91 92 rc = sqlite3PagerWrite(pPg);93 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3PagerWrite failed");94 95 /* Mutate a byte to ensure it's considered modified */96 unsigned char *pData = (unsigned char*)sqlite3PagerGetData(pPg);97 TEST_ASSERT_NOT_NULL(pData);98 pData[0] = (unsigned char)(pData[0] ^ 0x5A);99 100 sqlite3PagerUnref(pPg);101 102 /* Now close. This should sync hot-journal (if any), rollback and unlock. */103 rc = sqlite3PagerClose(pPager, NULL);104 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);105 106 /* Database should be healthy and openable. */107 assertDbOpensAndSelect1(zDb);108 109 cleanupDbFiles(zDb);110}111 112/* Test: Close with a non-NULL sqlite3* argument (no WAL expected). */113void test_sqlite3PagerClose_with_db_argument(void){114 char zDb[512];115 makeTempDbPath(zDb, sizeof(zDb), "withdb");116 cleanupDbFiles(zDb);117 118 /* Open a public sqlite3 connection to the same file. */119 sqlite3 *db = 0;120 int rc = sqlite3_open(zDb, &db);121 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");122 123 /* Independently open a pager on the same file. */124 Pager *pPager = openPagerOnFile(zDb);125 126 /* Close the pager, providing the db pointer (WAL is not active, but this127 lightly exercises the db/flags path inside sqlite3PagerClose). */128 rc = sqlite3PagerClose(pPager, db);129 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);130 131 /* The sqlite3 connection should still be usable. */132 rc = sqlite3_exec(db, "SELECT 1;", 0, 0, 0);133 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);134 135 sqlite3_close(db);136 cleanupDbFiles(zDb);137}138 139int main(void){140 UNITY_BEGIN();141 RUN_TEST(test_sqlite3PagerClose_basic);142 RUN_TEST(test_sqlite3PagerClose_with_dirty_page);143 RUN_TEST(test_sqlite3PagerClose_with_db_argument);144 return UNITY_END();145}