AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6extern int sqlite3MemdbInit(void);7extern int test_memdbWrite(sqlite3_file *pFile, const void *z, int iAmt, sqlite_int64 iOfst);8 9static sqlite3_file* open_memdb_file(const char *zName, void **ppBuf){10 int rc;11 sqlite3_vfs *pVfs;12 sqlite3_file *pFile = 0;13 int outFlags = 0;14 15 /* Ensure memdb VFS is registered */16 rc = sqlite3MemdbInit();17 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);18 19 pVfs = sqlite3_vfs_find("memdb");20 TEST_ASSERT_NOT_NULL(pVfs);21 22 *ppBuf = sqlite3_malloc64(pVfs->szOsFile);23 TEST_ASSERT_NOT_NULL(*ppBuf);24 memset(*ppBuf, 0, pVfs->szOsFile);25 26 pFile = (sqlite3_file*)(*ppBuf);27 rc = pVfs->xOpen(pVfs, zName, pFile,28 SQLITE_OPEN_MAIN_DB | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,29 &outFlags);30 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);31 TEST_ASSERT_NOT_NULL(pFile->pMethods);32 return pFile;33}34 35static void close_memdb_file(sqlite3_file *pFile, void *pBuf){36 int rc = pFile->pMethods->xClose(pFile);37 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);38 sqlite3_free(pBuf);39}40 41void setUp(void) {42 /* No-op */43}44void tearDown(void) {45 /* No-op */46}47 48/* Test 1: Zero-length write is a no-op and returns SQLITE_OK, size remains 0 */49void test_memdbWrite_zero_length_noop(void) {50 void *pBuf = NULL;51 sqlite3_file *pFile = open_memdb_file("/t_zero", &pBuf);52 53 int rc = test_memdbWrite(pFile, "", 0, 0);54 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);55 56 sqlite3_int64 sz = -1;57 rc = pFile->pMethods->xFileSize(pFile, &sz);58 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);59 TEST_ASSERT_EQUAL_INT64(0, sz);60 61 close_memdb_file(pFile, pBuf);62}63 64/* Test 2: Basic write and read-back */65void test_memdbWrite_basic_write_and_readback(void) {66 void *pBuf = NULL;67 sqlite3_file *pFile = open_memdb_file("/t_basic", &pBuf);68 69 const char *data = "hello";70 int len = (int)strlen(data);71 72 int rc = test_memdbWrite(pFile, data, len, 0);73 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);74 75 sqlite3_int64 sz = -1;76 rc = pFile->pMethods->xFileSize(pFile, &sz);77 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);78 TEST_ASSERT_EQUAL_INT(len, (int)sz);79 80 char buf[16];81 memset(buf, 0xAA, sizeof(buf));82 rc = pFile->pMethods->xRead(pFile, buf, len, 0);83 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);84 TEST_ASSERT_EQUAL_INT(0, memcmp(buf, data, len));85 86 close_memdb_file(pFile, pBuf);87}88 89/* Test 3: Write with a gap should zero-fill the gap */90void test_memdbWrite_gap_zero_fill(void) {91 void *pBuf = NULL;92 sqlite3_file *pFile = open_memdb_file("/t_gap", &pBuf);93 94 const char *data = "abc";95 int len = (int)strlen(data);96 sqlite3_int64 ofst = 10;97 98 int rc = test_memdbWrite(pFile, data, len, ofst);99 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);100 101 sqlite3_int64 sz = -1;102 rc = pFile->pMethods->xFileSize(pFile, &sz);103 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);104 TEST_ASSERT_EQUAL_INT64(ofst + len, sz);105 106 unsigned char buf[32];107 memset(buf, 0xFF, sizeof(buf));108 rc = pFile->pMethods->xRead(pFile, buf, (int)(ofst + len), 0);109 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);110 111 /* First 'ofst' bytes should be zero */112 for (int i = 0; i < (int)ofst; i++){113 TEST_ASSERT_EQUAL_UINT8(0, buf[i]);114 }115 /* Then the data */116 TEST_ASSERT_EQUAL_INT(0, memcmp(buf + ofst, data, len));117 118 close_memdb_file(pFile, pBuf);119}120 121/* Test 4: Respect SQLITE_FCNTL_SIZE_LIMIT (writing beyond should return SQLITE_FULL) */122void test_memdbWrite_respects_size_limit(void) {123 void *pBuf = NULL;124 sqlite3_file *pFile = open_memdb_file("/t_limit", &pBuf);125 126 sqlite3_int64 limit = 8;127 int rc = pFile->pMethods->xFileControl(pFile, SQLITE_FCNTL_SIZE_LIMIT, &limit);128 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);129 TEST_ASSERT_EQUAL_INT64(8, limit);130 131 unsigned char big[32];132 for (int i = 0; i < (int)sizeof(big); i++) big[i] = (unsigned char)i;133 134 rc = test_memdbWrite(pFile, big, 16, 0);135 TEST_ASSERT_EQUAL_INT(SQLITE_FULL, rc);136 137 /* Size should remain 0 */138 sqlite3_int64 sz = -1;139 rc = pFile->pMethods->xFileSize(pFile, &sz);140 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);141 TEST_ASSERT_EQUAL_INT64(0, sz);142 143 close_memdb_file(pFile, pBuf);144}145 146/* Test 5: READONLY flag leads to SQLITE_IOERR_WRITE */147void test_memdbWrite_readonly_returns_error(void) {148 int rc;149 sqlite3 *db = NULL;150 151 /* Ensure memdb VFS is registered so we can open DB on it */152 rc = sqlite3MemdbInit();153 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);154 155 rc = sqlite3_open_v2("file:ro_test?vfs=memdb", &db,156 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI, 0);157 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);158 TEST_ASSERT_NOT_NULL(db);159 160 /* Prepare a small buffer and deserialize as READONLY */161 int sz = 16;162 unsigned char *pData = (unsigned char*)sqlite3_malloc64(sz);163 TEST_ASSERT_NOT_NULL(pData);164 for (int i = 0; i < sz; i++) pData[i] = (unsigned char)(0xA0 + i);165 166 rc = sqlite3_deserialize(db, "main", pData, sz, sz, SQLITE_DESERIALIZE_READONLY);167 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);168 169 /* Get the underlying file pointer */170 sqlite3_file *pFile = NULL;171 rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &pFile);172 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);173 TEST_ASSERT_NOT_NULL(pFile);174 175 /* Attempt to write should return SQLITE_IOERR_WRITE */176 const char c = 'X';177 int wrc = test_memdbWrite(pFile, &c, 1, 0);178 TEST_ASSERT_EQUAL_INT(SQLITE_IOERR_WRITE, wrc);179 180 rc = sqlite3_close(db);181 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);182 183 /* Since we used SQLITE_DESERIALIZE_READONLY (no FREEONCLOSE), we own the buffer */184 sqlite3_free(pData);185}186 187int main(void) {188 UNITY_BEGIN();189 RUN_TEST(test_memdbWrite_zero_length_noop);190 RUN_TEST(test_memdbWrite_basic_write_and_readback);191 RUN_TEST(test_memdbWrite_gap_zero_fill);192 RUN_TEST(test_memdbWrite_respects_size_limit);193 RUN_TEST(test_memdbWrite_readonly_returns_error);194 return UNITY_END();195}