File size: 6,526 Bytes
7510827 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
#include "sqliteInt.h"
#include "unity.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Wrapper for the static function provided by the build harness */
extern void test_errorMPrintf(sqlite3_context *pCtx, const char *zFmt, ...);
/* Unity fixtures */
void setUp(void) {
/* no-op */
}
void tearDown(void) {
/* no-op */
}
/* Helpers to register UDFs that invoke test_errorMPrintf */
static void xErr_basic(sqlite3_context *ctx, int argc, sqlite3_value **argv){
/* Expect 4 args: text, int, int64, double */
const char *name = (const char*)sqlite3_value_text(argv[0]);
int a = sqlite3_value_int(argv[1]);
sqlite3_int64 b = sqlite3_value_int64(argv[2]);
double c = sqlite3_value_double(argv[3]);
test_errorMPrintf(ctx, "Name:%s Int:%d I64:%lld Dbl:%.2f", name, a, b, c);
}
static void xErr_percent(sqlite3_context *ctx, int argc, sqlite3_value **argv){
/* No args needed. Just a percent literal test. */
(void)argc; (void)argv;
test_errorMPrintf(ctx, "Rate: %d%%", 100);
}
static void xErr_null(sqlite3_context *ctx, int argc, sqlite3_value **argv){
/* 1 arg: possibly NULL text */
const char *s = (const char*)sqlite3_value_text(argv[0]); /* may be NULL */
test_errorMPrintf(ctx, "S=%s", s);
}
static void xErr_long(sqlite3_context *ctx, int argc, sqlite3_value **argv){
/* 1 arg: long text string */
const char *s = (const char*)sqlite3_value_text(argv[0]);
test_errorMPrintf(ctx, "Long:%s", s);
}
/* Utility: prepare, step and capture error message on failure.
Returns a heap-allocated copy of sqlite3_errmsg(db) when step returns SQLITE_ERROR.
Caller must sqlite3_free on the returned string (allocated with sqlite3_malloc). */
static char* step_and_capture_errmsg(sqlite3 *db, sqlite3_stmt *stmt, int *pRc){
int rc = sqlite3_step(stmt);
if( pRc ) *pRc = rc;
if( rc==SQLITE_ERROR ){
const char *z = sqlite3_errmsg(db);
size_t n = strlen(z);
char *copy = (char*)sqlite3_malloc((int)n+1);
if( copy ){
memcpy(copy, z, n+1);
}
return copy;
}
return NULL;
}
/* Test 1: Basic formatting with multiple specifiers */
void test_errorMPrintf_formats_basic(void){
sqlite3 *db = 0;
sqlite3_stmt *stmt = 0;
int rc;
rc = sqlite3_open(":memory:", &db);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
rc = sqlite3_create_function_v2(db, "t_basic", 4, SQLITE_UTF8, NULL,
xErr_basic, NULL, NULL, NULL);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
const char *sql = "SELECT t_basic('Alice', 42, 1234567890123, 3.14159)";
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
int stepRc = SQLITE_OK;
char *errmsg = step_and_capture_errmsg(db, stmt, &stepRc);
TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, stepRc);
/* Expect rounding to two decimals for %.2f */
const char *expected = "Name:Alice Int:42 I64:1234567890123 Dbl:3.14";
TEST_ASSERT_NOT_NULL(errmsg);
TEST_ASSERT_EQUAL_STRING(expected, errmsg);
sqlite3_free(errmsg);
sqlite3_finalize(stmt);
sqlite3_close(db);
}
/* Test 2: Literal percent "%%" */
void test_errorMPrintf_handles_percent_literal(void){
sqlite3 *db = 0;
sqlite3_stmt *stmt = 0;
int rc;
rc = sqlite3_open(":memory:", &db);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
rc = sqlite3_create_function_v2(db, "t_pct", 0, SQLITE_UTF8, NULL,
xErr_percent, NULL, NULL, NULL);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
const char *sql = "SELECT t_pct()";
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
int stepRc = SQLITE_OK;
char *errmsg = step_and_capture_errmsg(db, stmt, &stepRc);
TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, stepRc);
const char *expected = "Rate: 100%";
TEST_ASSERT_NOT_NULL(errmsg);
TEST_ASSERT_EQUAL_STRING(expected, errmsg);
sqlite3_free(errmsg);
sqlite3_finalize(stmt);
sqlite3_close(db);
}
/* Test 3: NULL string is rendered as "(NULL)" by sqlite3_mprintf family */
void test_errorMPrintf_null_string_becomes_NULL_literal(void){
sqlite3 *db = 0;
sqlite3_stmt *stmt = 0;
int rc;
rc = sqlite3_open(":memory:", &db);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
rc = sqlite3_create_function_v2(db, "t_null", 1, SQLITE_UTF8, NULL,
xErr_null, NULL, NULL, NULL);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
const char *sql = "SELECT t_null(NULL)";
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
int stepRc = SQLITE_OK;
char *errmsg = step_and_capture_errmsg(db, stmt, &stepRc);
TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, stepRc);
const char *expected = "S=(NULL)";
TEST_ASSERT_NOT_NULL(errmsg);
TEST_ASSERT_EQUAL_STRING(expected, errmsg);
sqlite3_free(errmsg);
sqlite3_finalize(stmt);
sqlite3_close(db);
}
/* Test 4: Very long message to exercise allocation and correctness */
void test_errorMPrintf_long_message(void){
sqlite3 *db = 0;
sqlite3_stmt *stmt = 0;
int rc;
/* Build a long input string */
const int N = 50000;
char *longInput = (char*)malloc((size_t)N + 1);
TEST_ASSERT_NOT_NULL(longInput);
memset(longInput, 'A', (size_t)N);
longInput[N] = '\0';
/* Expected: "Long:" + longInput */
size_t prefixLen = 5; /* "Long:" */
char *expected = (char*)malloc(prefixLen + (size_t)N + 1);
TEST_ASSERT_NOT_NULL(expected);
memcpy(expected, "Long:", prefixLen);
memcpy(expected + prefixLen, longInput, (size_t)N + 1);
rc = sqlite3_open(":memory:", &db);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
rc = sqlite3_create_function_v2(db, "t_long", 1, SQLITE_UTF8, NULL,
xErr_long, NULL, NULL, NULL);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
rc = sqlite3_prepare_v2(db, "SELECT t_long(?)", -1, &stmt, NULL);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
rc = sqlite3_bind_text(stmt, 1, longInput, -1, SQLITE_TRANSIENT);
TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
int stepRc = SQLITE_OK;
char *errmsg = step_and_capture_errmsg(db, stmt, &stepRc);
TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, stepRc);
TEST_ASSERT_NOT_NULL(errmsg);
TEST_ASSERT_EQUAL_STRING(expected, errmsg);
sqlite3_free(errmsg);
sqlite3_finalize(stmt);
sqlite3_close(db);
free(expected);
free(longInput);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_errorMPrintf_formats_basic);
RUN_TEST(test_errorMPrintf_handles_percent_literal);
RUN_TEST(test_errorMPrintf_null_string_becomes_NULL_literal);
RUN_TEST(test_errorMPrintf_long_message);
return UNITY_END();
} |