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 <stdarg.h>8#include <unistd.h>9 10/* Helper to begin capturing stdout into a temporary file.11 Returns 0 on success, non-zero on error. */12static int start_capture_stdout(int *pSavedFd, FILE **pTmpFile){13 int saved = -1;14 FILE *tmp = NULL;15 if( pSavedFd==NULL || pTmpFile==NULL ) return -1;16 17 fflush(stdout);18 saved = dup(fileno(stdout));19 if( saved<0 ) return -1;20 21 tmp = tmpfile();22 if( tmp==NULL ){23 close(saved);24 return -1;25 }26 27 if( dup2(fileno(tmp), fileno(stdout))<0 ){28 fclose(tmp);29 close(saved);30 return -1;31 }32 33 *pSavedFd = saved;34 *pTmpFile = tmp;35 return 0;36}37 38/* Helper to finish capturing stdout.39 Restores stdout, reads captured data into *pOut (malloc'd), null-terminated.40 Returns 0 on success, non-zero on error. */41static int end_capture_stdout(int savedFd, FILE *tmp, char **pOut){42 long sz = 0;43 size_t nRead = 0;44 char *buf = NULL;45 46 if( pOut ) *pOut = NULL;47 48 fflush(stdout);49 50 if( fseek(tmp, 0, SEEK_END)!=0 ){51 /* Restore stdout before returning error */52 dup2(savedFd, fileno(stdout));53 close(savedFd);54 fclose(tmp);55 return -1;56 }57 sz = ftell(tmp);58 if( sz < 0 ) sz = 0;59 if( fseek(tmp, 0, SEEK_SET)!=0 ){60 dup2(savedFd, fileno(stdout));61 close(savedFd);62 fclose(tmp);63 return -1;64 }65 66 buf = (char*)malloc((size_t)sz + 1);67 if( buf==NULL ){68 dup2(savedFd, fileno(stdout));69 close(savedFd);70 fclose(tmp);71 return -1;72 }73 if( sz>0 ){74 nRead = fread(buf, 1, (size_t)sz, tmp);75 }else{76 nRead = 0;77 }78 buf[nRead] = '\0';79 80 /* Restore stdout and cleanup */81 dup2(savedFd, fileno(stdout));82 close(savedFd);83 fclose(tmp);84 85 if( pOut ) *pOut = buf;86 else free(buf);87 88 return 0;89}90 91void setUp(void) {92 /* Setup code here, or leave empty */93}94void tearDown(void) {95 /* Cleanup code here, or leave empty */96}97 98#ifdef SQLITE_OS_TRACE_PROC99#define SKIP_IF_OS_TRACE() do { \100 TEST_IGNORE_MESSAGE("SQLITE_OS_TRACE_PROC defined; sqlite3DebugPrintf does not write to stdout."); \101 return; \102} while(0)103#else104#define SKIP_IF_OS_TRACE() do {} while(0)105#endif106 107/* Test: basic string without formatting */108void test_sqlite3DebugPrintf_basic_string(void){109 SKIP_IF_OS_TRACE();110 int saved;111 FILE *tmp;112 char *out = NULL;113 114 if( start_capture_stdout(&saved, &tmp)!=0 ){115 TEST_FAIL_MESSAGE("Failed to start stdout capture");116 }117 /* Do not assert while stdout is redirected */118 sqlite3DebugPrintf("Hello, world");119 if( end_capture_stdout(saved, tmp, &out)!=0 ){120 TEST_FAIL_MESSAGE("Failed to end stdout capture");121 }122 123 TEST_ASSERT_NOT_NULL(out);124 TEST_ASSERT_EQUAL_STRING("Hello, world", out);125 free(out);126}127 128/* Test: empty string prints nothing */129void test_sqlite3DebugPrintf_empty_string(void){130 SKIP_IF_OS_TRACE();131 int saved;132 FILE *tmp;133 char *out = NULL;134 135 if( start_capture_stdout(&saved, &tmp)!=0 ){136 TEST_FAIL_MESSAGE("Failed to start stdout capture");137 }138 sqlite3DebugPrintf("");139 if( end_capture_stdout(saved, tmp, &out)!=0 ){140 TEST_FAIL_MESSAGE("Failed to end stdout capture");141 }142 143 TEST_ASSERT_NOT_NULL(out);144 TEST_ASSERT_EQUAL_STRING("", out);145 free(out);146}147 148/* Test: %lld support and sign handling */149void test_sqlite3DebugPrintf_long_long_formats(void){150 SKIP_IF_OS_TRACE();151 int saved;152 FILE *tmp;153 char *out = NULL;154 long long max = 9223372036854775807LL;155 156 if( start_capture_stdout(&saved, &tmp)!=0 ){157 TEST_FAIL_MESSAGE("Failed to start stdout capture");158 }159 sqlite3DebugPrintf("%lld %lld", -1LL, max);160 if( end_capture_stdout(saved, tmp, &out)!=0 ){161 TEST_FAIL_MESSAGE("Failed to end stdout capture");162 }163 164 TEST_ASSERT_NOT_NULL(out);165 TEST_ASSERT_EQUAL_STRING("-1 9223372036854775807", out);166 free(out);167}168 169/* Test: mixed formats including string, int and literal percent */170void test_sqlite3DebugPrintf_mixed_and_percent(void){171 SKIP_IF_OS_TRACE();172 int saved;173 FILE *tmp;174 char *out = NULL;175 176 if( start_capture_stdout(&saved, &tmp)!=0 ){177 TEST_FAIL_MESSAGE("Failed to start stdout capture");178 }179 sqlite3DebugPrintf("Value: %s %d%% done", "ok", 42);180 if( end_capture_stdout(saved, tmp, &out)!=0 ){181 TEST_FAIL_MESSAGE("Failed to end stdout capture");182 }183 184 TEST_ASSERT_NOT_NULL(out);185 TEST_ASSERT_EQUAL_STRING("Value: ok 42% done", out);186 free(out);187}188 189/* Test: SQLite-specific %q escaping (single quotes doubled) */190void test_sqlite3DebugPrintf_q_escape(void){191 SKIP_IF_OS_TRACE();192 int saved;193 FILE *tmp;194 char *out = NULL;195 196 if( start_capture_stdout(&saved, &tmp)!=0 ){197 TEST_FAIL_MESSAGE("Failed to start stdout capture");198 }199 sqlite3DebugPrintf("%q", "O'Brien");200 if( end_capture_stdout(saved, tmp, &out)!=0 ){201 TEST_FAIL_MESSAGE("Failed to end stdout capture");202 }203 204 TEST_ASSERT_NOT_NULL(out);205 TEST_ASSERT_EQUAL_STRING("O''Brien", out);206 free(out);207}208 209/* Test: floating point formatting with precision */210void test_sqlite3DebugPrintf_float_precision(void){211 SKIP_IF_OS_TRACE();212 int saved;213 FILE *tmp;214 char *out = NULL;215 216 if( start_capture_stdout(&saved, &tmp)!=0 ){217 TEST_FAIL_MESSAGE("Failed to start stdout capture");218 }219 sqlite3DebugPrintf("Pi=%.2f", 3.14159);220 if( end_capture_stdout(saved, tmp, &out)!=0 ){221 TEST_FAIL_MESSAGE("Failed to end stdout capture");222 }223 224 TEST_ASSERT_NOT_NULL(out);225 TEST_ASSERT_EQUAL_STRING("Pi=3.14", out);226 free(out);227}228 229/* Test: %c with a non-ASCII codepoint (UTF-8 euro sign U+20AC) */230void test_sqlite3DebugPrintf_utf8_char(void){231 SKIP_IF_OS_TRACE();232 int saved;233 FILE *tmp;234 char *out = NULL;235 236 if( start_capture_stdout(&saved, &tmp)!=0 ){237 TEST_FAIL_MESSAGE("Failed to start stdout capture");238 }239 sqlite3DebugPrintf("%c", 0x20AC); /* U+20AC (€) */240 if( end_capture_stdout(saved, tmp, &out)!=0 ){241 TEST_FAIL_MESSAGE("Failed to end stdout capture");242 }243 244 TEST_ASSERT_NOT_NULL(out);245 /* Expect UTF-8 bytes for euro sign */246 TEST_ASSERT_EQUAL_STRING("\xE2\x82\xAC", out);247 free(out);248}249 250int main(void) {251 UNITY_BEGIN();252 RUN_TEST(test_sqlite3DebugPrintf_basic_string);253 RUN_TEST(test_sqlite3DebugPrintf_empty_string);254 RUN_TEST(test_sqlite3DebugPrintf_long_long_formats);255 RUN_TEST(test_sqlite3DebugPrintf_mixed_and_percent);256 RUN_TEST(test_sqlite3DebugPrintf_q_escape);257 RUN_TEST(test_sqlite3DebugPrintf_float_precision);258 RUN_TEST(test_sqlite3DebugPrintf_utf8_char);259 return UNITY_END();260}