AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Unity setup/teardown */7void setUp(void) {8 /* No global setup required */9}10void tearDown(void) {11 /* No global teardown required */12}13 14/* Helper: open an in-memory db and assert success */15static sqlite3* open_memdb(void){16 sqlite3 *db = 0;17 int rc = sqlite3_open(":memory:", &db);18 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open(:memory:) failed");19 TEST_ASSERT_NOT_NULL(db);20 return db;21}22 23#ifndef NDEBUG /* The target function is only available in non-NDEBUG builds */24 25void test_sqlite3SchemaMutexHeld_uninitialized_db_returns_1(void){26 /* Create a zeroed sqlite3 struct to simulate uninitialized db. */27 sqlite3 *db = (sqlite3*)sqlite3_malloc(sizeof(sqlite3));28 TEST_ASSERT_NOT_NULL(db);29 memset(db, 0, sizeof(sqlite3));30 31 int rc = sqlite3SchemaMutexHeld(db, 0, NULL);32 TEST_ASSERT_EQUAL_INT(1, rc);33 34 sqlite3_free(db);35}36 37void test_sqlite3SchemaMutexHeld_returns_0_without_db_mutex_main(void){38#if SQLITE_THREADSAFE39 sqlite3 *db = open_memdb();40 41 /* Do not enter db->mutex. Expect 0 for main schema (iDb==0). */42 int held = sqlite3SchemaMutexHeld(db, 0, NULL);43 TEST_ASSERT_EQUAL_INT(0, held);44 45 sqlite3_close(db);46#else47 TEST_IGNORE_MESSAGE("Skipping: SQLITE_THREADSAFE==0, sqlite3_mutex_held may always be true");48#endif49}50 51void test_sqlite3SchemaMutexHeld_returns_0_without_db_mutex_temp(void){52#if SQLITE_THREADSAFE53 sqlite3 *db = open_memdb();54 55 /* Do not enter db->mutex. Even for temp (iDb==1), expect 0 because db mutex not held. */56 int held = sqlite3SchemaMutexHeld(db, 1, NULL);57 TEST_ASSERT_EQUAL_INT(0, held);58 59 sqlite3_close(db);60#else61 TEST_IGNORE_MESSAGE("Skipping: SQLITE_THREADSAFE==0, sqlite3_mutex_held may always be true");62#endif63}64 65void test_sqlite3SchemaMutexHeld_temp_schema_returns_1_with_db_mutex_held(void){66 sqlite3 *db = open_memdb();67 68 /* Hold db mutex, expect 1 for TEMP schema (iDb==1). */69 sqlite3_mutex_enter(db->mutex);70 int held = sqlite3SchemaMutexHeld(db, 1, NULL);71 sqlite3_mutex_leave(db->mutex);72 73 TEST_ASSERT_EQUAL_INT(1, held);74 75 sqlite3_close(db);76}77 78void test_sqlite3SchemaMutexHeld_pSchema_overrides_iDb_temp(void){79 sqlite3 *db = open_memdb();80 81 /* Use pSchema for TEMP (index 1), but pass bogus iDb. With db->mutex held, expect 1. */82 Schema *tempSchema = db->aDb[1].pSchema;83 TEST_ASSERT_NOT_NULL(tempSchema);84 85 sqlite3_mutex_enter(db->mutex);86 int held = sqlite3SchemaMutexHeld(db, 9999, tempSchema); /* iDb overridden to 1 */87 sqlite3_mutex_leave(db->mutex);88 89 TEST_ASSERT_EQUAL_INT(1, held);90 91 sqlite3_close(db);92}93 94void test_sqlite3SchemaMutexHeld_main_schema_returns_1_after_btree_enter(void){95 sqlite3 *db = open_memdb();96 97 /* Hold db mutex, then explicitly enter main Btree. Expect return 1. */98 sqlite3_mutex_enter(db->mutex);99 100 /* main schema index is 0; ensure pBt exists */101 TEST_ASSERT_TRUE(db->nDb >= 1);102 TEST_ASSERT_NOT_NULL(db->aDb[0].pBt);103 104 /* Before locking the btree, result may be 0 (shared-cache) or 1 (non-sharable). */105 int beforeHeld = sqlite3SchemaMutexHeld(db, 0, db->aDb[0].pSchema);106 107 /* Lock the btree for main schema, which guarantees the condition for return 1 */108 sqlite3BtreeEnter(db->aDb[0].pBt);109 int afterHeld = sqlite3SchemaMutexHeld(db, 0, db->aDb[0].pSchema);110 sqlite3BtreeLeave(db->aDb[0].pBt);111 112 sqlite3_mutex_leave(db->mutex);113 114 /* After locking, the function must return 1 */115 TEST_ASSERT_EQUAL_INT(1, afterHeld);116 /* The "before" value should be less-or-equal to "after" (0->1 or 1->1) */117 TEST_ASSERT_TRUE(beforeHeld == 0 || beforeHeld == 1);118 TEST_ASSERT_LESS_OR_EQUAL_INT(afterHeld, afterHeld); /* trivially true; keeps Unity happy on types */119 TEST_ASSERT_TRUE_MESSAGE(beforeHeld <= afterHeld, "Result after BtreeEnter should not decrease");120}121 122void test_sqlite3SchemaMutexHeld_pSchema_overrides_iDb_main_with_btree_enter(void){123 sqlite3 *db = open_memdb();124 125 Schema *mainSchema = db->aDb[0].pSchema;126 TEST_ASSERT_NOT_NULL(mainSchema);127 128 sqlite3_mutex_enter(db->mutex);129 130 /* Enter the main btree to ensure the function returns 1 for main schema */131 sqlite3BtreeEnter(db->aDb[0].pBt);132 int held = sqlite3SchemaMutexHeld(db, -12345, mainSchema); /* iDb overridden to 0 */133 sqlite3BtreeLeave(db->aDb[0].pBt);134 135 sqlite3_mutex_leave(db->mutex);136 137 TEST_ASSERT_EQUAL_INT(1, held);138 139 sqlite3_close(db);140}141 142#else143/* If NDEBUG is defined, the target function is not available. */144void test_sqlite3SchemaMutexHeld_unavailable_in_release_build(void){145 TEST_IGNORE_MESSAGE("sqlite3SchemaMutexHeld is compiled only in non-NDEBUG builds");146}147#endif /* NDEBUG */148 149int main(void){150 UNITY_BEGIN();151 152#ifndef NDEBUG153 RUN_TEST(test_sqlite3SchemaMutexHeld_uninitialized_db_returns_1);154 RUN_TEST(test_sqlite3SchemaMutexHeld_returns_0_without_db_mutex_main);155 RUN_TEST(test_sqlite3SchemaMutexHeld_returns_0_without_db_mutex_temp);156 RUN_TEST(test_sqlite3SchemaMutexHeld_temp_schema_returns_1_with_db_mutex_held);157 RUN_TEST(test_sqlite3SchemaMutexHeld_pSchema_overrides_iDb_temp);158 RUN_TEST(test_sqlite3SchemaMutexHeld_main_schema_returns_1_after_btree_enter);159 RUN_TEST(test_sqlite3SchemaMutexHeld_pSchema_overrides_iDb_main_with_btree_enter);160#else161 RUN_TEST(test_sqlite3SchemaMutexHeld_unavailable_in_release_build);162#endif163 164 return UNITY_END();165}