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

/* Wrapper for the static function under test (provided in build as per instructions) */
extern int test_renameResolveTrigger(Parse *pParse);

/* Helpers */
static void execSQL(sqlite3 *db, const char *sql){
  int rc = sqlite3_exec(db, sql, 0, 0, 0);
  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
}

static void initParseAndTriggerWithTable(sqlite3 **pDb, Parse *pParse, Trigger **ppTrig, const char *zTable){
  sqlite3 *db = 0;
  int rc = sqlite3_open(":memory:", &db);
  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
  /* Ensure a simple table exists */
  char sql[256];
  sqlite3_snprintf(sizeof(sql), sql, "CREATE TABLE %s(a, b);", zTable);
  execSQL(db, sql);

  memset(pParse, 0, sizeof(*pParse));
  pParse->db = db;

  Trigger *pTrig = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger));
  TEST_ASSERT_NOT_NULL(pTrig);

  Table *pTab = sqlite3FindTable(db, zTable, "main");
  TEST_ASSERT_NOT_NULL(pTab);
  pTrig->pTabSchema = pTab->pSchema;
  pTrig->table = sqlite3DbStrDup(db, zTable);
  TEST_ASSERT_NOT_NULL(pTrig->table);
  pTrig->op = TK_DELETE; /* default op; individual tests may override */
  pTrig->pWhen = 0;
  pTrig->step_list = 0;

  pParse->pNewTrigger = pTrig;

  *pDb = db;
  *ppTrig = pTrig;
}

static Token makeToken(const char *z){
  Token t;
  t.z = z;
  t.n = (int)strlen(z);
  return t;
}

void setUp(void) {
  /* Empty setup */
}
void tearDown(void) {
  /* Empty teardown */
}

/* Test 1: Basic successful resolution for a simple trigger with no WHEN and no steps */
void test_renameResolveTrigger_basic_ok(void){
  sqlite3 *db = 0;
  Parse sParse;
  Trigger *pTrig = 0;

  initParseAndTriggerWithTable(&db, &sParse, &pTrig, "t1");
  /* Change op to check that eTriggerOp is set */
  pTrig->op = TK_INSERT;

  int rc = test_renameResolveTrigger(&sParse);
  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);
  TEST_ASSERT_NOT_NULL(sParse.pTriggerTab);
  TEST_ASSERT_EQUAL_INT(TK_INSERT, sParse.eTriggerOp);

  /* Cleanup */
  sqlite3DbFree(db, pTrig->table);
  sqlite3DbFree(db, pTrig);
  sqlite3_close(db);
}

/* Test 2: WHEN clause is a constant expression -> success */
void test_renameResolveTrigger_when_constant_ok(void){
  sqlite3 *db = 0;
  Parse sParse;
  Trigger *pTrig = 0;

  initParseAndTriggerWithTable(&db, &sParse, &pTrig, "t1");

  /* WHEN 1 */
  Token t1 = makeToken("1");
  pTrig->pWhen = sqlite3ExprAlloc(db, TK_INTEGER, &t1, 0);
  TEST_ASSERT_NOT_NULL(pTrig->pWhen);

  int rc = test_renameResolveTrigger(&sParse);
  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);

  /* Cleanup */
  sqlite3ExprDelete(db, pTrig->pWhen);
  sqlite3DbFree(db, pTrig->table);
  sqlite3DbFree(db, pTrig);
  sqlite3_close(db);
}

/* Test 3: WHEN clause references a non-existent column -> expect error */
void test_renameResolveTrigger_when_bad_column_error(void){
  sqlite3 *db = 0;
  Parse sParse;
  Trigger *pTrig = 0;

  initParseAndTriggerWithTable(&db, &sParse, &pTrig, "t1");

  /* WHEN nosuchcol */
  Token tBad = makeToken("nosuchcol");
  pTrig->pWhen = sqlite3ExprAlloc(db, TK_ID, &tBad, 0);
  TEST_ASSERT_NOT_NULL(pTrig->pWhen);

  int rc = test_renameResolveTrigger(&sParse);
  TEST_ASSERT_NOT_EQUAL_INT(SQLITE_OK, rc);

  /* Cleanup */
  sqlite3ExprDelete(db, pTrig->pWhen);
  sqlite3DbFree(db, pTrig->table);
  sqlite3DbFree(db, pTrig);
  sqlite3_close(db);
}

/* Test 4: Trigger step contains a minimal SELECT -> success */
void test_renameResolveTrigger_step_with_select_ok(void){
  sqlite3 *db = 0;
  Parse sParse;
  Trigger *pTrig = 0;

  initParseAndTriggerWithTable(&db, &sParse, &pTrig, "t1");

  TriggerStep *pStep = (TriggerStep*)sqlite3DbMallocZero(db, sizeof(TriggerStep));
  TEST_ASSERT_NOT_NULL(pStep);
  /* Minimal select */
  pStep->pSelect = sqlite3SelectNew(&sParse, 0, 0, 0, 0, 0, 0, 0, 0);
  TEST_ASSERT_NOT_NULL(pStep->pSelect);

  pTrig->step_list = pStep;

  int rc = test_renameResolveTrigger(&sParse);
  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);

  /* Cleanup */
  sqlite3SelectDelete(db, pStep->pSelect);
  sqlite3DbFree(db, pStep);
  sqlite3DbFree(db, pTrig->table);
  sqlite3DbFree(db, pTrig);
  sqlite3_close(db);
}

/* Test 5: Trigger step contains a SrcList referencing existing table and a WHERE that resolves -> success */
void test_renameResolveTrigger_step_with_src_and_where_ok(void){
  sqlite3 *db = 0;
  Parse sParse;
  Trigger *pTrig = 0;

  initParseAndTriggerWithTable(&db, &sParse, &pTrig, "t1");

  TriggerStep *pStep = (TriggerStep*)sqlite3DbMallocZero(db, sizeof(TriggerStep));
  TEST_ASSERT_NOT_NULL(pStep);

  /* Build a minimal SrcList with one term "t1" (in "main") */
  SrcList *pSrc = (SrcList*)sqlite3DbMallocZero(db, sizeof(SrcList));
  TEST_ASSERT_NOT_NULL(pSrc);
  pSrc->nSrc = 1;
  pSrc->a[0].zName = sqlite3DbStrDup(db, "t1");
  TEST_ASSERT_NOT_NULL(pSrc->a[0].zName);
  pSrc->a[0].zDatabase = sqlite3DbStrDup(db, "main");
  TEST_ASSERT_NOT_NULL(pSrc->a[0].zDatabase);

  pStep->pSrc = pSrc;

  /* WHERE a (column of t1) */
  Token tA = makeToken("a");
  pStep->pWhere = sqlite3ExprAlloc(db, TK_ID, &tA, 0);
  TEST_ASSERT_NOT_NULL(pStep->pWhere);

  pTrig->step_list = pStep;

  int rc = test_renameResolveTrigger(&sParse);
  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);

  /* Cleanup original (the function deletes its duplicate internally) */
  sqlite3ExprDelete(db, pStep->pWhere);
  sqlite3SrcListDelete(db, pStep->pSrc);
  sqlite3DbFree(db, pStep);
  sqlite3DbFree(db, pTrig->table);
  sqlite3DbFree(db, pTrig);
  sqlite3_close(db);
}

int main(void){
  UNITY_BEGIN();
  RUN_TEST(test_renameResolveTrigger_basic_ok);
  RUN_TEST(test_renameResolveTrigger_when_constant_ok);
  RUN_TEST(test_renameResolveTrigger_when_bad_column_error);
  RUN_TEST(test_renameResolveTrigger_step_with_select_ok);
  RUN_TEST(test_renameResolveTrigger_step_with_src_and_where_ok);
  return UNITY_END();
}