AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Unity setup/teardown */7void setUp(void) {8 /* No global setup needed */9}10void tearDown(void) {11 /* No global teardown needed */12}13 14/* Helper to allocate a Table with nCol columns and provided notNull flags.15 notNullFlags must have length nCol. */16static Table* makeTableWithNotNulls(int nCol, const u8 *notNullFlags){17 Table *pTab = (Table*)malloc(sizeof(Table));18 TEST_ASSERT_NOT_NULL(pTab);19 memset(pTab, 0, sizeof(Table));20 pTab->nCol = (i16)nCol;21 if( nCol>0 ){22 Column *aCol = (Column*)malloc(sizeof(Column)*nCol);23 TEST_ASSERT_NOT_NULL(aCol);24 memset(aCol, 0, sizeof(Column)*nCol);25 for(int i=0; i<nCol; i++){26 aCol[i].notNull = notNullFlags ? notNullFlags[i] : 0;27 }28 pTab->aCol = aCol;29 }30 return pTab;31}32 33static void freeTable(Table *pTab){34 if( pTab ){35 if( pTab->aCol ) free(pTab->aCol);36 free(pTab);37 }38}39 40/* 1) Constants should be detected as non-nullable (return 0) */41void test_sqlite3ExprCanBeNull_constants_return_false(void){42 Expr eInt; memset(&eInt, 0, sizeof(eInt)); eInt.op = TK_INTEGER;43 Expr eStr; memset(&eStr, 0, sizeof(eStr)); eStr.op = TK_STRING;44 Expr eFlt; memset(&eFlt, 0, sizeof(eFlt)); eFlt.op = TK_FLOAT;45 Expr eBlob; memset(&eBlob, 0, sizeof(eBlob)); eBlob.op = TK_BLOB;46 47 TEST_ASSERT_EQUAL_INT(0, sqlite3ExprCanBeNull(&eInt));48 TEST_ASSERT_EQUAL_INT(0, sqlite3ExprCanBeNull(&eStr));49 TEST_ASSERT_EQUAL_INT(0, sqlite3ExprCanBeNull(&eFlt));50 TEST_ASSERT_EQUAL_INT(0, sqlite3ExprCanBeNull(&eBlob));51}52 53/* 2) Unary operators should be skipped and the child inspected */54void test_sqlite3ExprCanBeNull_unary_skips_to_child(void){55 Expr child; memset(&child, 0, sizeof(child)); child.op = TK_INTEGER;56 57 Expr unaryMinus; memset(&unaryMinus, 0, sizeof(unaryMinus));58 unaryMinus.op = TK_UMINUS;59 unaryMinus.pLeft = &child;60 61 Expr unaryPlus; memset(&unaryPlus, 0, sizeof(unaryPlus));62 unaryPlus.op = TK_UPLUS;63 unaryPlus.pLeft = &unaryMinus; /* Chain two unary ops */64 65 TEST_ASSERT_EQUAL_INT(0, sqlite3ExprCanBeNull(&unaryMinus));66 TEST_ASSERT_EQUAL_INT(0, sqlite3ExprCanBeNull(&unaryPlus));67}68 69/* 3) TK_REGISTER should resolve to op2 and be treated accordingly */70void test_sqlite3ExprCanBeNull_register_resolves_op2(void){71 Expr e; memset(&e, 0, sizeof(e));72 e.op = TK_REGISTER;73 e.op2 = TK_FLOAT; /* Underlying expression is a constant float */74 TEST_ASSERT_EQUAL_INT(0, sqlite3ExprCanBeNull(&e));75 76 e.op2 = TK_BLOB;77 TEST_ASSERT_EQUAL_INT(0, sqlite3ExprCanBeNull(&e));78}79 80/* 4) TK_COLUMN behavior based on column nullability and EP_CanBeNull flag */81void test_sqlite3ExprCanBeNull_column_nullability(void){82 /* Create a table with two columns:83 - col0 allows NULL (notNull=0)84 - col1 is NOT NULL (notNull=1) */85 u8 nn[2] = {0, 1};86 Table *pTab = makeTableWithNotNulls(2, nn);87 88 /* Column 0 (nullable) => function returns 1 (can be null) */89 Expr eCol0; memset(&eCol0, 0, sizeof(eCol0));90 eCol0.op = TK_COLUMN;91 eCol0.y.pTab = pTab;92 eCol0.iColumn = 0;93 eCol0.flags = 0;94 TEST_ASSERT_EQUAL_INT(1, sqlite3ExprCanBeNull(&eCol0));95 96 /* Column 1 (NOT NULL) => function returns 0 (cannot be null) */97 Expr eCol1; memset(&eCol1, 0, sizeof(eCol1));98 eCol1.op = TK_COLUMN;99 eCol1.y.pTab = pTab;100 eCol1.iColumn = 1;101 eCol1.flags = 0;102 TEST_ASSERT_EQUAL_INT(0, sqlite3ExprCanBeNull(&eCol1));103 104 freeTable(pTab);105}106 107/* 5) EP_CanBeNull overrides NOT NULL column constraint */108void test_sqlite3ExprCanBeNull_column_with_EP_CanBeNull_flag(void){109 u8 nn[1] = {1}; /* NOT NULL column */110 Table *pTab = makeTableWithNotNulls(1, nn);111 112 Expr eCol; memset(&eCol, 0, sizeof(eCol));113 eCol.op = TK_COLUMN;114 eCol.y.pTab = pTab;115 eCol.iColumn = 0;116 eCol.flags = EP_CanBeNull; /* Force possible null due to outer join, etc. */117 118 TEST_ASSERT_EQUAL_INT(1, sqlite3ExprCanBeNull(&eCol));119 120 freeTable(pTab);121}122 123/* 6) Rowid (iColumn<0) should be considered non-null */124void test_sqlite3ExprCanBeNull_rowid_nonnull(void){125 u8 nn[1] = {0};126 Table *pTab = makeTableWithNotNulls(1, nn);127 128 Expr eRowid; memset(&eRowid, 0, sizeof(eRowid));129 eRowid.op = TK_COLUMN;130 eRowid.y.pTab = pTab;131 eRowid.iColumn = -1; /* rowid */132 eRowid.flags = 0;133 134 TEST_ASSERT_EQUAL_INT(0, sqlite3ExprCanBeNull(&eRowid));135 136 freeTable(pTab);137}138 139/* 7) Default case: expression types not explicitly handled (e.g., TK_NULL) return 1 */140void test_sqlite3ExprCanBeNull_default_returns_true(void){141 Expr e; memset(&e, 0, sizeof(e));142 e.op = TK_NULL; /* Default case goes to 'return 1' */143 TEST_ASSERT_EQUAL_INT(1, sqlite3ExprCanBeNull(&e));144}145 146/* Main */147int main(void){148 UNITY_BEGIN();149 RUN_TEST(test_sqlite3ExprCanBeNull_constants_return_false);150 RUN_TEST(test_sqlite3ExprCanBeNull_unary_skips_to_child);151 RUN_TEST(test_sqlite3ExprCanBeNull_register_resolves_op2);152 RUN_TEST(test_sqlite3ExprCanBeNull_column_nullability);153 RUN_TEST(test_sqlite3ExprCanBeNull_column_with_EP_CanBeNull_flag);154 RUN_TEST(test_sqlite3ExprCanBeNull_rowid_nonnull);155 RUN_TEST(test_sqlite3ExprCanBeNull_default_returns_true);156 return UNITY_END();157}