File size: 4,316 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
#include "sqliteInt.h"
#include "unity.h"
#include <stdlib.h>
#include <string.h>

/* Global test database connection */
static sqlite3 *gDb = NULL;

/* Wrapper provided by the module for testing the static function */
extern void test_renameTestSchema(
  Parse *pParse,
  const char *zDb,
  int bTemp,
  const char *zWhen,
  int bNoDQS
);

/* Provide sqlite_rename_test function so nested parses compile and run */
static void xRenameTestFunc(sqlite3_context *ctx, int argc, sqlite3_value **argv){
  /* This function is used by nested parse SQL: return NULL to satisfy "=NULL" */
  SQLITE_USE(argc);
  SQLITE_USE(argv);
  sqlite3_result_null(ctx);
}

/* Helper: initialize a fresh Parse object bound to gDb */
static void initParse(Parse *p){
  memset(p, 0, sizeof(*p));
  p->db = gDb;
}

/* Helper: cleanup VDBE and error message in Parse to avoid leaks */
static void cleanupParse(Parse *p){
  if( p->pVdbe ){
    sqlite3VdbeDelete(p->pVdbe);
    p->pVdbe = 0;
  }
  if( p->zErrMsg ){
    sqlite3DbFree(p->db, p->zErrMsg);
    p->zErrMsg = 0;
  }
}

void setUp(void) {
  int rc = sqlite3_open(":memory:", &gDb);
  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);

  /* Register sqlite_rename_test(name in SQL) with 6 args */
  rc = sqlite3_create_function(gDb, "sqlite_rename_test", 6,
                               SQLITE_UTF8, 0,
                               xRenameTestFunc, 0, 0);
  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
}

void tearDown(void) {
  if( gDb ){
    int rc = sqlite3_close(gDb);
    TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
    gDb = NULL;
  }
}

/* Basic sanity: sets colNamesSet, creates a VDBE, and emits some code */
void test_renameTestSchema_sets_colNamesSet_and_creates_vdbe(void){
  Parse p;
  initParse(&p);

  test_renameTestSchema(&p, "main", 0, "during rename", 0);

  /* Verify colNamesSet is set */
  TEST_ASSERT_EQUAL_INT(1, p.colNamesSet);

  /* Verify a VDBE was created and has some ops */
  TEST_ASSERT_NOT_NULL(p.pVdbe);
  int nOp = sqlite3VdbeCurrentAddr(p.pVdbe);
  TEST_ASSERT_TRUE(nOp > 0);

  cleanupParse(&p);
}

/* bTemp affects the number of nested parses: 0 => two queries, 1 => one query */
void test_renameTestSchema_bTemp_affects_instruction_count(void){
  Parse p1, p2;
  initParse(&p1);
  initParse(&p2);

  /* One nested parse (temp db only) */
  test_renameTestSchema(&p1, "temp", 1, "phase A", 0);
  TEST_ASSERT_EQUAL_INT(1, p1.colNamesSet);
  TEST_ASSERT_NOT_NULL(p1.pVdbe);
  int nOp1 = sqlite3VdbeCurrentAddr(p1.pVdbe);
  TEST_ASSERT_TRUE(nOp1 > 0);

  /* Two nested parses (main + temp) */
  test_renameTestSchema(&p2, "main", 0, "phase B", 0);
  TEST_ASSERT_EQUAL_INT(1, p2.colNamesSet);
  TEST_ASSERT_NOT_NULL(p2.pVdbe);
  int nOp2 = sqlite3VdbeCurrentAddr(p2.pVdbe);
  TEST_ASSERT_TRUE(nOp2 > 0);

  /* Expect more ops when bTemp==0 due to the extra nested SELECT */
  TEST_ASSERT_TRUE(nOp2 > nOp1);

  cleanupParse(&p1);
  cleanupParse(&p2);
}

/* Using "temp" db name with bTemp==1 should still function correctly */
void test_renameTestSchema_temp_db_only(void){
  Parse p;
  initParse(&p);

  test_renameTestSchema(&p, "temp", 1, "temp-only", 1 /* bNoDQS */);

  TEST_ASSERT_EQUAL_INT(1, p.colNamesSet);
  TEST_ASSERT_NOT_NULL(p.pVdbe);
  int nOp = sqlite3VdbeCurrentAddr(p.pVdbe);
  TEST_ASSERT_TRUE(nOp > 0);

  cleanupParse(&p);
}

/* Ensure NULL zWhen and varying bNoDQS do not crash and still generate code */
void test_renameTestSchema_null_when_and_noDQS_variations(void){
  Parse pA, pB;
  initParse(&pA);
  initParse(&pB);

  /* zWhen NULL, bNoDQS = 0 */
  test_renameTestSchema(&pA, "main", 0, NULL, 0);
  TEST_ASSERT_EQUAL_INT(1, pA.colNamesSet);
  TEST_ASSERT_NOT_NULL(pA.pVdbe);
  int nOpA = sqlite3VdbeCurrentAddr(pA.pVdbe);
  TEST_ASSERT_TRUE(nOpA > 0);

  /* zWhen NULL, bNoDQS = 1 */
  test_renameTestSchema(&pB, "main", 0, NULL, 1);
  TEST_ASSERT_EQUAL_INT(1, pB.colNamesSet);
  TEST_ASSERT_NOT_NULL(pB.pVdbe);
  int nOpB = sqlite3VdbeCurrentAddr(pB.pVdbe);
  TEST_ASSERT_TRUE(nOpB > 0);

  cleanupParse(&pA);
  cleanupParse(&pB);
}

int main(void) {
  UNITY_BEGIN();
  RUN_TEST(test_renameTestSchema_sets_colNamesSet_and_creates_vdbe);
  RUN_TEST(test_renameTestSchema_bTemp_affects_instruction_count);
  RUN_TEST(test_renameTestSchema_temp_db_only);
  RUN_TEST(test_renameTestSchema_null_when_and_noDQS_variations);
  return UNITY_END();
}