AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <string.h>5#include <stdlib.h>6 7/* Unity setup/teardown */8void setUp(void) {9 /* No global setup needed */10}11 12void tearDown(void) {13 /* No global teardown needed */14}15 16/* Helper: Open an in-memory database and assert success */17static sqlite3* open_db(void){18 sqlite3 *db = 0;19 int rc = sqlite3_open(":memory:", &db);20 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");21 TEST_ASSERT_NOT_NULL_MESSAGE(db, "sqlite3_open returned NULL db");22 return db;23}24 25/* Helper: Initialize a Parse object for a given db */26static void init_parse(Parse *pParse, sqlite3 *db){27 memset(pParse, 0, sizeof(*pParse));28 pParse->db = db;29 /* pParse->rc defaults to SQLITE_OK (0) */30}31 32/* A VFS xOpen that always fails to simulate I/O errors on open */33static int failvfs_xOpen(sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFile,34 int flags, int *pOutFlags){35 UNUSED_PARAMETER(pVfs);36 UNUSED_PARAMETER(zName);37 UNUSED_PARAMETER(pFile);38 UNUSED_PARAMETER(flags);39 if( pOutFlags ) *pOutFlags = 0;40 return SQLITE_IOERR;41}42 43/* Test: Successful open should create a temp btree and return 0 */44static void test_sqlite3OpenTempDatabase_success_opens_temp_btree(void){45 sqlite3 *db = open_db();46 Parse parse;47 init_parse(&parse, db);48 49 /* Precondition: TEMP btree not yet open */50 TEST_ASSERT_NULL(db->aDb[1].pBt);51 52 int rc = sqlite3OpenTempDatabase(&parse);53 TEST_ASSERT_EQUAL_INT(0, rc);54 TEST_ASSERT_NOT_NULL_MESSAGE(db->aDb[1].pBt, "TEMP btree was not opened");55 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, parse.rc, "parse.rc should remain SQLITE_OK");56 57 sqlite3_close(db);58}59 60/* Test: When explain flag is set, function should do nothing and return 0 */61static void test_sqlite3OpenTempDatabase_noop_when_explain(void){62 sqlite3 *db = open_db();63 Parse parse;64 init_parse(&parse, db);65 66 /* Precondition: TEMP btree not yet open */67 TEST_ASSERT_NULL(db->aDb[1].pBt);68 69 parse.explain = 1; /* Force explain mode */70 int rc = sqlite3OpenTempDatabase(&parse);71 TEST_ASSERT_EQUAL_INT(0, rc);72 TEST_ASSERT_NULL_MESSAGE(db->aDb[1].pBt, "TEMP btree should not be opened in EXPLAIN mode");73 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, parse.rc, "parse.rc should remain SQLITE_OK in EXPLAIN mode");74 75 sqlite3_close(db);76}77 78/* Test: Calling when btree already open should be a no-op */79static void test_sqlite3OpenTempDatabase_noop_if_already_open(void){80 sqlite3 *db = open_db();81 Parse parse;82 init_parse(&parse, db);83 84 /* First call opens the TEMP database */85 int rc1 = sqlite3OpenTempDatabase(&parse);86 TEST_ASSERT_EQUAL_INT(0, rc1);87 TEST_ASSERT_NOT_NULL_MESSAGE(db->aDb[1].pBt, "TEMP btree was not opened on first call");88 Btree *pBtFirst = db->aDb[1].pBt;89 90 /* Second call should not change anything */91 int rc2 = sqlite3OpenTempDatabase(&parse);92 TEST_ASSERT_EQUAL_INT(0, rc2);93 TEST_ASSERT_EQUAL_PTR_MESSAGE(pBtFirst, db->aDb[1].pBt, "TEMP btree pointer should remain unchanged");94 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, parse.rc, "parse.rc should remain SQLITE_OK");95 96 sqlite3_close(db);97}98 99/* Test: Force sqlite3BtreeOpen() to fail via a VFS whose xOpen always fails */100static void test_sqlite3OpenTempDatabase_btree_open_failure_sets_error_and_rc(void){101 sqlite3 *db = open_db();102 Parse parse;103 init_parse(&parse, db);104 105 /* Ensure starting state has no TEMP btree */106 TEST_ASSERT_NULL(db->aDb[1].pBt);107 108 /* Build a failing VFS based on the default, overriding only xOpen */109 sqlite3_vfs *orig = db->pVfs;110 TEST_ASSERT_NOT_NULL_MESSAGE(orig, "db->pVfs is NULL");111 112 sqlite3_vfs failvfs = *orig; /* Shallow copy is sufficient for our purpose */113 failvfs.zName = "failvfs";114 failvfs.xOpen = failvfs_xOpen;115 116 /* Swap the connection's VFS to the failing one */117 db->pVfs = &failvfs;118 119 int rc = sqlite3OpenTempDatabase(&parse);120 121 /* Restore original VFS immediately after call */122 db->pVfs = orig;123 124 TEST_ASSERT_EQUAL_INT_MESSAGE(1, rc, "Function should return 1 on btree open failure");125 TEST_ASSERT_NULL_MESSAGE(db->aDb[1].pBt, "TEMP btree should not be set on failure");126 TEST_ASSERT_NOT_EQUAL_MESSAGE(SQLITE_OK, parse.rc, "parse.rc should be set to an error code");127 TEST_ASSERT_NOT_NULL_MESSAGE(parse.zErrMsg, "Error message should be set on failure");128 if( parse.zErrMsg ){129 /* Check error message contains expected text */130 TEST_ASSERT_NOT_NULL_MESSAGE(strstr(parse.zErrMsg, "unable to open a temporary database"),131 "Error message does not contain expected text");132 sqlite3DbFree(db, parse.zErrMsg);133 parse.zErrMsg = 0;134 }135 136 sqlite3_close(db);137}138 139int main(void){140 UNITY_BEGIN();141 RUN_TEST(test_sqlite3OpenTempDatabase_success_opens_temp_btree);142 RUN_TEST(test_sqlite3OpenTempDatabase_noop_when_explain);143 RUN_TEST(test_sqlite3OpenTempDatabase_noop_if_already_open);144 RUN_TEST(test_sqlite3OpenTempDatabase_btree_open_failure_sets_error_and_rc);145 return UNITY_END();146}