AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5#include <stdint.h>6 7/* The wrapper for the static function under test is provided in the module:8** void test_randomFunc(sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2);9*/10void test_randomFunc(sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2);11 12/* Global DB handle for Mem initialization */13static sqlite3 *gDb = NULL;14 15/* Helper to invoke test_randomFunc and return the produced 64-bit integer.16 Asserts that the Mem contains an integer. */17static sqlite3_int64 call_random_and_get_i64(void){18 sqlite3_context ctx;19 Mem m;20 memset(&ctx, 0, sizeof(ctx));21 memset(&m, 0, sizeof(m));22 23 /* Initialize the Mem with the database allocator */24 sqlite3VdbeMemInit(&m, gDb, 0);25 ctx.pOut = &m;26 27 /* Call the target function */28 test_randomFunc(&ctx, 0, NULL);29 30 /* Validate and extract result */31 TEST_ASSERT_TRUE_MESSAGE((m.flags & MEM_Int) != 0, "randomFunc did not set an integer result");32 sqlite3_int64 v = m.u.i;33 34 /* Cleanup */35 sqlite3VdbeMemRelease(&m);36 return v;37}38 39void setUp(void) {40 int rc = sqlite3_open(":memory:", &gDb);41 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "Failed to open in-memory SQLite database");42}43 44void tearDown(void) {45 if( gDb ){46 sqlite3_close(gDb);47 gDb = NULL;48 }49}50 51/* Basic property: returns an integer within bounds and never SMALLEST_INT64 */52void test_randomFunc_basic_properties(void){53 sqlite3_int64 v = call_random_and_get_i64();54 55 /* Must not be the smallest int64 */56 TEST_ASSERT_TRUE_MESSAGE(v != (sqlite3_int64)SMALLEST_INT64, "randomFunc returned SMALLEST_INT64");57 58 /* Sanity bounds checks (these are tautological for int64 but validate against our intended masks) */59 TEST_ASSERT_TRUE_MESSAGE(v <= (sqlite3_int64)LARGEST_INT64, "Value exceeds LARGEST_INT64");60 TEST_ASSERT_TRUE_MESSAGE(v >= (sqlite3_int64)(-LARGEST_INT64), "Value is less than -LARGEST_INT64");61}62 63/* Repeated calls: ensure variability and never SMALLEST_INT64 across many samples */64void test_randomFunc_many_calls_variability_and_no_smallest(void){65 const int N = 256;66 sqlite3_int64 first = call_random_and_get_i64();67 TEST_ASSERT_TRUE(first != (sqlite3_int64)SMALLEST_INT64);68 69 int sawDifferent = 0;70 for(int i=1; i<N; i++){71 sqlite3_int64 v = call_random_and_get_i64();72 TEST_ASSERT_TRUE_MESSAGE(v != (sqlite3_int64)SMALLEST_INT64, "Encountered SMALLEST_INT64 in random output");73 if( v != first ){74 sawDifferent = 1;75 }76 TEST_ASSERT_TRUE_MESSAGE(v <= (sqlite3_int64)LARGEST_INT64, "Value exceeds LARGEST_INT64");77 TEST_ASSERT_TRUE_MESSAGE(v >= (sqlite3_int64)(-LARGEST_INT64), "Value is less than -LARGEST_INT64");78 }79 TEST_ASSERT_TRUE_MESSAGE(sawDifferent, "randomFunc produced the same value across many calls (unexpected lack of variability)");80}81 82/* PRNG state save/restore should reproduce the same sequence of outputs */83void test_randomFunc_prng_save_restore_repeats_sequence(void){84 /* Save current PRNG state */85 sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SAVE);86 87 /* Generate a sequence */88 const int N = 64;89 sqlite3_int64 seqA[N];90 for(int i=0; i<N; i++){91 seqA[i] = call_random_and_get_i64();92 TEST_ASSERT_TRUE_MESSAGE(seqA[i] != (sqlite3_int64)SMALLEST_INT64, "SMALLEST_INT64 encountered in seqA");93 }94 95 /* Restore PRNG state and regenerate */96 sqlite3_test_control(SQLITE_TESTCTRL_PRNG_RESTORE);97 sqlite3_int64 seqB[N];98 for(int i=0; i<N; i++){99 seqB[i] = call_random_and_get_i64();100 TEST_ASSERT_TRUE_MESSAGE(seqB[i] != (sqlite3_int64)SMALLEST_INT64, "SMALLEST_INT64 encountered in seqB");101 }102 103 /* Compare sequences for equality */104 for(int i=0; i<N; i++){105 TEST_ASSERT_EQUAL_INT64_MESSAGE(seqA[i], seqB[i], "PRNG restore did not reproduce the same sequence");106 }107}108 109/* Optional: Reset PRNG and ensure a deterministic starting sequence comparison with itself */110void test_randomFunc_prng_reset_determinism_smoke(void){111 /* Reset PRNG to a known state */112 sqlite3_test_control(SQLITE_TESTCTRL_PRNG_RESET);113 114 /* Capture a short sequence */115 const int N = 8;116 sqlite3_int64 seq1[N];117 for(int i=0; i<N; i++){118 seq1[i] = call_random_and_get_i64();119 TEST_ASSERT_TRUE_MESSAGE(seq1[i] != (sqlite3_int64)SMALLEST_INT64, "SMALLEST_INT64 encountered after PRNG reset");120 }121 122 /* Reset again and capture another short sequence; they should match */123 sqlite3_test_control(SQLITE_TESTCTRL_PRNG_RESET);124 sqlite3_int64 seq2[N];125 for(int i=0; i<N; i++){126 seq2[i] = call_random_and_get_i64();127 TEST_ASSERT_TRUE_MESSAGE(seq2[i] != (sqlite3_int64)SMALLEST_INT64, "SMALLEST_INT64 encountered after PRNG reset (second)");128 }129 130 for(int i=0; i<N; i++){131 TEST_ASSERT_EQUAL_INT64_MESSAGE(seq1[i], seq2[i], "PRNG reset did not produce the same initial sequence");132 }133}134 135int main(void) {136 UNITY_BEGIN();137 RUN_TEST(test_randomFunc_basic_properties);138 RUN_TEST(test_randomFunc_many_calls_variability_and_no_smallest);139 RUN_TEST(test_randomFunc_prng_save_restore_repeats_sequence);140 RUN_TEST(test_randomFunc_prng_reset_determinism_smoke);141 return UNITY_END();142}