AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdio.h>4#include <stdlib.h>5#include <string.h>6#include <unistd.h>7#include <errno.h>8 9/* Wrapper provided by the module for the static function */10extern void test_jsonShowParse(JsonParse *pParse);11 12/* stdout capture helpers (POSIX) */13static int saved_stdout_fd = -1;14static int capture_pipe_fd[2] = {-1, -1};15 16static void start_capture(void){17 fflush(stdout);18 if( pipe(capture_pipe_fd) != 0 ){19 /* If pipe fails, tests cannot proceed meaningfully */20 perror("pipe");21 exit(1);22 }23 saved_stdout_fd = dup(fileno(stdout));24 if( saved_stdout_fd < 0 ){25 perror("dup");26 exit(1);27 }28 if( dup2(capture_pipe_fd[1], fileno(stdout)) < 0 ){29 perror("dup2");30 exit(1);31 }32 close(capture_pipe_fd[1]);33 capture_pipe_fd[1] = -1;34}35 36static char *end_capture(void){37 /* Restore stdout before doing any Unity assertions */38 fflush(stdout);39 if( saved_stdout_fd >= 0 ){40 if( dup2(saved_stdout_fd, fileno(stdout)) < 0 ){41 perror("dup2 restore");42 exit(1);43 }44 close(saved_stdout_fd);45 saved_stdout_fd = -1;46 }47 48 /* Read all from pipe */49 char *buf = NULL;50 size_t cap = 0;51 size_t n = 0;52 char tmp[256];53 ssize_t r;54 for(;;){55 r = read(capture_pipe_fd[0], tmp, sizeof(tmp));56 if( r < 0 ){57 if( errno == EINTR ) continue;58 perror("read");59 break;60 }61 if( r == 0 ) break; /* EOF */62 if( n + (size_t)r + 1 > cap ){63 size_t newCap = cap ? cap*2 : 512;64 while( newCap < n + (size_t)r + 1 ) newCap *= 2;65 char *newBuf = (char*)realloc(buf, newCap);66 if( newBuf == NULL ){67 free(buf);68 buf = NULL;69 break;70 }71 buf = newBuf;72 cap = newCap;73 }74 memcpy(buf + n, tmp, (size_t)r);75 n += (size_t)r;76 }77 if( capture_pipe_fd[0] >= 0 ){78 close(capture_pipe_fd[0]);79 capture_pipe_fd[0] = -1;80 }81 if( buf ){82 buf[n] = '\n'; /* In case final write didn't end with newline? */83 buf[n] = '\0';84 }else{85 buf = strdup("");86 }87 return buf;88}89 90static char* capture_show_parse(JsonParse *p){91 start_capture();92 test_jsonShowParse(p);93 return end_capture();94}95 96/* Unity fixtures */97void setUp(void) {98 /* no-op */99}100void tearDown(void) {101 /* no-op */102}103 104/* Helper to initialize a JsonParse with minimal fields used by jsonShowParse */105static void initParse(JsonParse *p, unsigned char *a, unsigned nBlob, unsigned nBlobAlloc, int delta){106 memset(p, 0, sizeof(*p));107 p->aBlob = a;108 p->nBlob = nBlob;109 p->nBlobAlloc = nBlobAlloc;110 p->delta = delta;111}112 113/* Tests */114 115void test_jsonShowParse_null_pointer(void){116 char *out = capture_show_parse(NULL);117 TEST_ASSERT_NOT_NULL(out);118 TEST_ASSERT_EQUAL_STRING("NULL pointer\n", out);119 free(out);120}121 122void test_jsonShowParse_empty_blob(void){123 JsonParse p;124 unsigned char data[1] = {0};125 initParse(&p, data, 0, 7, 2);126 127 char *out = capture_show_parse(&p);128 TEST_ASSERT_NOT_NULL(out);129 const char *exp =130 "nBlobAlloc = 7\n"131 "nBlob = 0\n"132 "delta = 2\n";133 TEST_ASSERT_EQUAL_STRING(exp, out);134 free(out);135}136 137void test_jsonShowParse_single_null_element(void){138 JsonParse p;139 unsigned char data[1] = {140 0x00 /* high nibble 0 (size 0), low nibble 0 (NULL) */141 };142 initParse(&p, data, 1, 1, 0);143 144 char *out = capture_show_parse(&p);145 TEST_ASSERT_NOT_NULL(out);146 const char *exp =147 "nBlobAlloc = 1\n"148 "nBlob = 1\n"149 "delta = 0\n"150 "content (bytes 0..0):\n"151 " 0: 00 <-- null\n";152 TEST_ASSERT_EQUAL_STRING(exp, out);153 free(out);154}155 156void test_jsonShowParse_text_abc(void){157 JsonParse p;158 unsigned char data[4] = {159 0x37, /* high nibble 3 (size 3), low nibble 7 (TEXT) */160 0x61, 0x62, 0x63 /* 'a','b','c' */161 };162 initParse(&p, data, 4, 4, 0);163 164 char *out = capture_show_parse(&p);165 TEST_ASSERT_NOT_NULL(out);166 const char *exp =167 "nBlobAlloc = 4\n"168 "nBlob = 4\n"169 "delta = 0\n"170 "content (bytes 0..3):\n"171 " 0: 37 61 62 63 <-- text: \"abc\"\n";172 TEST_ASSERT_EQUAL_STRING(exp, out);173 free(out);174}175 176void test_jsonShowParse_array_null_true(void){177 JsonParse p;178 unsigned char data[3] = {179 0x2b, /* high nibble 2 (size 2), low nibble 11 (ARRAY) */180 0x00, /* NULL */181 0x01 /* TRUE */182 };183 initParse(&p, data, 3, 3, 0);184 185 char *out = capture_show_parse(&p);186 TEST_ASSERT_NOT_NULL(out);187 const char *exp =188 "nBlobAlloc = 3\n"189 "nBlob = 3\n"190 "delta = 0\n"191 "content (bytes 0..2):\n"192 " 0: 2b 00 01 <-- array, 2 bytes\n"193 " 1: 00 <-- null\n"194 " 2: 01 <-- true\n";195 TEST_ASSERT_EQUAL_STRING(exp, out);196 free(out);197}198 199void test_jsonShowParse_invalid_node_size(void){200 JsonParse p;201 unsigned char data[1] = {202 0x57 /* high nibble 5 (size 5), low nibble 7 (TEXT) but no payload available */203 };204 initParse(&p, data, 1, 1, 0);205 206 char *out = capture_show_parse(&p);207 TEST_ASSERT_NOT_NULL(out);208 const char *exp =209 "nBlobAlloc = 1\n"210 "nBlob = 1\n"211 "delta = 0\n"212 "content (bytes 0..0):\n"213 " 0: 57 ERROR invalid node size\n";214 TEST_ASSERT_EQUAL_STRING(exp, out);215 free(out);216}217 218void test_jsonShowParse_uses_nBlobAlloc_for_header_then_restores(void){219 JsonParse p;220 unsigned char data[5] = {221 0xc7, /* high nibble 12 (size in next byte), low nibble 7 (TEXT) */222 0x03, /* size = 3 */223 0x78, 0x79, 0x7a /* 'x','y','z' */224 };225 /* Make nBlob smaller than full element to force use of nBlobAlloc during size parsing */226 initParse(&p, data, 2, 5, 0);227 228 char *out = capture_show_parse(&p);229 TEST_ASSERT_NOT_NULL(out);230 const char *exp =231 "nBlobAlloc = 5\n"232 "nBlob = 2\n"233 "delta = 0\n"234 "content (bytes 0..1):\n"235 " 0: c7 03 78 79 7a <-- text: \"xyz\"\n";236 TEST_ASSERT_EQUAL_STRING(exp, out);237 free(out);238}239 240int main(void){241 UNITY_BEGIN();242 RUN_TEST(test_jsonShowParse_null_pointer);243 RUN_TEST(test_jsonShowParse_empty_blob);244 RUN_TEST(test_jsonShowParse_single_null_element);245 RUN_TEST(test_jsonShowParse_text_abc);246 RUN_TEST(test_jsonShowParse_array_null_true);247 RUN_TEST(test_jsonShowParse_invalid_node_size);248 RUN_TEST(test_jsonShowParse_uses_nBlobAlloc_for_header_then_restores);249 return UNITY_END();250}