AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdio.h>5#include <stdlib.h>6#include <string.h>7#include <time.h>8 9#ifdef _WIN3210#include <io.h>11#define unlink _unlink12#endif13 14/* Some platforms may not have unistd.h; unlink is provided above for Windows */15#ifndef _WIN3216#include <unistd.h>17#endif18 19/* Prototypes of the target and helpers (available when SQLITE_MEMDEBUG is enabled) */20#ifdef SQLITE_MEMDEBUG21extern void sqlite3MemdebugDump(const char *zFilename);22extern void sqlite3MemSetDefault(void);23extern void sqlite3MemdebugSettitle(const char *zTitle);24extern void sqlite3MemdebugBacktrace(int depth);25#endif26 27static char gTmpPath[256];28static int gTmpCounter = 0;29 30static const char* make_temp_path(void){31 /* Create a simple unique-ish filename in the current working directory */32 unsigned r = (unsigned)time(NULL);33 /* Use counter to avoid collisions within same second */34 snprintf(gTmpPath, sizeof(gTmpPath), "memdebugdump_test_%u_%d.log", r, gTmpCounter++);35 return gTmpPath;36}37 38static char* read_entire_file(const char *path, size_t *pN){39 FILE *f = fopen(path, "rb");40 if( !f ) return NULL;41 if( fseek(f, 0, SEEK_END)!=0 ){42 fclose(f);43 return NULL;44 }45 long n = ftell(f);46 if( n < 0 ){47 fclose(f);48 return NULL;49 }50 rewind(f);51 char *buf = (char*)malloc((size_t)n + 1);52 if( !buf ){53 fclose(f);54 return NULL;55 }56 size_t got = fread(buf, 1, (size_t)n, f);57 fclose(f);58 buf[got] = '\0';59 if( pN ) *pN = got;60 return buf;61}62 63void setUp(void) {64#ifdef SQLITE_MEMDEBUG65 /* Ensure mem2 allocator is active for this test run */66 sqlite3_shutdown();67 sqlite3MemSetDefault();68 int rc = sqlite3_initialize();69 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_initialize failed");70 /* Disable backtrace output for stability across platforms */71 sqlite3MemdebugBacktrace(0);72#endif73}74 75void tearDown(void) {76#ifdef SQLITE_MEMDEBUG77 sqlite3_shutdown();78#endif79}80 81#ifdef SQLITE_MEMDEBUG82 83static void assert_file_contains(const char *path, const char *needle){84 size_t n = 0;85 char *content = read_entire_file(path, &n);86 TEST_ASSERT_NOT_NULL_MESSAGE(content, "Failed to read dump file");87 int has = (strstr(content, needle) != NULL);88 free(content);89 TEST_ASSERT_TRUE_MESSAGE(has, "Expected substring not found in dump output");90}91 92static void assert_file_not_contains(const char *path, const char *needle){93 size_t n = 0;94 char *content = read_entire_file(path, &n);95 TEST_ASSERT_NOT_NULL_MESSAGE(content, "Failed to read dump file");96 int has = (strstr(content, needle) != NULL);97 free(content);98 TEST_ASSERT_FALSE_MESSAGE(has, "Unexpected substring found in dump output");99}100 101void test_sqlite3MemdebugDump_basic_counts(void) {102 const char *path = make_temp_path();103 sqlite3MemdebugDump(path);104 105 /* File should exist and contain "COUNTS:" */106 assert_file_contains(path, "COUNTS:");107 108 unlink(path);109}110 111void test_sqlite3MemdebugDump_includes_allocation_and_title(void) {112 const char *title = "Title_A";113 const int sz = 37; /* Non-multiple of 8 to check exact byte count in output */114 115 sqlite3MemdebugSettitle(title);116 void *p = sqlite3_malloc(sz);117 TEST_ASSERT_NOT_NULL(p);118 119 const char *path = make_temp_path();120 sqlite3MemdebugDump(path);121 122 /* Verify the dump contains the allocation size and the title */123 char expectSize[64];124 snprintf(expectSize, sizeof(expectSize), "**** %d bytes", sz);125 assert_file_contains(path, expectSize);126 /* The "from <title>" should be present */127 char expectTitle[128];128 snprintf(expectTitle, sizeof(expectTitle), "from %s", title);129 assert_file_contains(path, expectTitle);130 131 sqlite3_free(p);132 unlink(path);133}134 135void test_sqlite3MemdebugDump_free_allocation_not_listed(void) {136 /* Use unique titles to avoid accidental collisions between tests */137 char titleRemain[64], titleGone[64];138 snprintf(titleRemain, sizeof(titleRemain), "Remain_%d", gTmpCounter);139 snprintf(titleGone, sizeof(titleGone), "Gone_%d", gTmpCounter);140 141 const int szRemain = 173;142 const int szGone = 991;143 144 sqlite3MemdebugSettitle(titleRemain);145 void *pRemain = sqlite3_malloc(szRemain);146 TEST_ASSERT_NOT_NULL(pRemain);147 148 sqlite3MemdebugSettitle(titleGone);149 void *pGone = sqlite3_malloc(szGone);150 TEST_ASSERT_NOT_NULL(pGone);151 152 /* Free the 'gone' allocation before dumping */153 sqlite3_free(pGone);154 155 const char *path = make_temp_path();156 sqlite3MemdebugDump(path);157 158 /* Should contain the remaining allocation details */159 char expectRemainSize[64];160 snprintf(expectRemainSize, sizeof(expectRemainSize), "**** %d bytes", szRemain);161 assert_file_contains(path, expectRemainSize);162 163 char expectRemainTitle[128];164 snprintf(expectRemainTitle, sizeof(expectRemainTitle), "from %s", titleRemain);165 assert_file_contains(path, expectRemainTitle);166 167 /* Should not contain the freed allocation details */168 char expectGoneSize[64];169 snprintf(expectGoneSize, sizeof(expectGoneSize), "**** %d bytes", szGone);170 assert_file_not_contains(path, expectGoneSize);171 172 char expectGoneTitle[128];173 snprintf(expectGoneTitle, sizeof(expectGoneTitle), "from %s", titleGone);174 assert_file_not_contains(path, expectGoneTitle);175 176 sqlite3_free(pRemain);177 unlink(path);178}179 180#else181 182void test_sqlite3MemdebugDump_placeholder(void) {183 TEST_IGNORE_MESSAGE("SQLITE_MEMDEBUG is not enabled; mem2 allocator and sqlite3MemdebugDump are unavailable.");184}185 186#endif /* SQLITE_MEMDEBUG */187 188int main(void) {189 UNITY_BEGIN();190#ifdef SQLITE_MEMDEBUG191 RUN_TEST(test_sqlite3MemdebugDump_basic_counts);192 RUN_TEST(test_sqlite3MemdebugDump_includes_allocation_and_title);193 RUN_TEST(test_sqlite3MemdebugDump_free_allocation_not_listed);194#else195 RUN_TEST(test_sqlite3MemdebugDump_placeholder);196#endif197 return UNITY_END();198}