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