diff options
Diffstat (limited to 'src/libs/dutil/test/DUtilUnitTest/SceUtilTest.cpp')
-rw-r--r-- | src/libs/dutil/test/DUtilUnitTest/SceUtilTest.cpp | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/src/libs/dutil/test/DUtilUnitTest/SceUtilTest.cpp b/src/libs/dutil/test/DUtilUnitTest/SceUtilTest.cpp new file mode 100644 index 00000000..75b9222a --- /dev/null +++ b/src/libs/dutil/test/DUtilUnitTest/SceUtilTest.cpp | |||
@@ -0,0 +1,488 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
2 | |||
3 | #include "precomp.h" | ||
4 | |||
5 | #include <sqlce_oledb.h> | ||
6 | #include <sceutil.h> | ||
7 | |||
8 | using namespace System; | ||
9 | using namespace Xunit; | ||
10 | using namespace WixTest; | ||
11 | |||
12 | #define ASSIGN_INDEX_STRUCT(a, b, c) {a.wzName = c; a.rgColumns = b; a.cColumns = countof(b);}; | ||
13 | |||
14 | namespace DutilTests | ||
15 | { | ||
16 | enum TABLES | ||
17 | { | ||
18 | TABLE_A, | ||
19 | TABLE_COUNT | ||
20 | }; | ||
21 | |||
22 | enum TABLE_A_COLUMNS | ||
23 | { | ||
24 | TABLE_A_KEY, | ||
25 | TABLE_A_BINARY, | ||
26 | TABLE_A_DWORD, | ||
27 | TABLE_A_QWORD, | ||
28 | TABLE_A_BOOL, | ||
29 | TABLE_A_STRING, | ||
30 | TABLE_A_DWORD_NULLABLE, | ||
31 | TABLE_A_INITIAL_COLUMNS, | ||
32 | |||
33 | TABLE_A_EXTRA_STRING = TABLE_A_INITIAL_COLUMNS, | ||
34 | TABLE_A_FINAL_COLUMNS | ||
35 | }; | ||
36 | |||
37 | struct TableARowValue | ||
38 | { | ||
39 | DWORD dwAutoGenKey; | ||
40 | |||
41 | BYTE *pbBinary; | ||
42 | DWORD cBinary; | ||
43 | |||
44 | DWORD dw; | ||
45 | DWORD64 qw; | ||
46 | BOOL f; | ||
47 | LPWSTR scz; | ||
48 | |||
49 | BOOL fNullablePresent; | ||
50 | DWORD dwNullable; | ||
51 | |||
52 | BOOL fSchemaV2; | ||
53 | LPWSTR sczExtra; | ||
54 | }; | ||
55 | |||
56 | public ref class SceUtil | ||
57 | { | ||
58 | public: | ||
59 | void ReleaseSceSchema(SCE_DATABASE_SCHEMA *pdsSchema) | ||
60 | { | ||
61 | DWORD dwTable; | ||
62 | |||
63 | for (dwTable = 0; dwTable < pdsSchema->cTables; ++dwTable) | ||
64 | { | ||
65 | ReleaseNullMem(pdsSchema->rgTables[dwTable].rgColumns); | ||
66 | ReleaseNullMem(pdsSchema->rgTables[dwTable].rgIndexes); | ||
67 | } | ||
68 | |||
69 | ReleaseMem(pdsSchema->rgTables); | ||
70 | |||
71 | return; | ||
72 | } | ||
73 | |||
74 | void SetupSchema(SCE_DATABASE_SCHEMA *pSchema, BOOL fIncludeExtended) | ||
75 | { | ||
76 | pSchema->cTables = TABLE_COUNT; | ||
77 | pSchema->rgTables = static_cast<SCE_TABLE_SCHEMA*>(MemAlloc(TABLE_COUNT * sizeof(SCE_TABLE_SCHEMA), TRUE)); | ||
78 | NativeAssert::True(pSchema->rgTables != NULL); | ||
79 | |||
80 | pSchema->rgTables[TABLE_A].wzName = L"TableA"; | ||
81 | pSchema->rgTables[TABLE_A].cColumns = fIncludeExtended ? TABLE_A_FINAL_COLUMNS : TABLE_A_INITIAL_COLUMNS; | ||
82 | pSchema->rgTables[TABLE_A].cIndexes = 2; | ||
83 | |||
84 | for (DWORD i = 0; i < pSchema->cTables; ++i) | ||
85 | { | ||
86 | pSchema->rgTables[i].rgColumns = static_cast<SCE_COLUMN_SCHEMA*>(MemAlloc(sizeof(SCE_COLUMN_SCHEMA) * pSchema->rgTables[i].cColumns, TRUE)); | ||
87 | NativeAssert::True(pSchema->rgTables[i].rgColumns != NULL); | ||
88 | |||
89 | pSchema->rgTables[i].rgIndexes = static_cast<SCE_INDEX_SCHEMA*>(MemAlloc(sizeof(SCE_COLUMN_SCHEMA) * pSchema->rgTables[i].cIndexes, TRUE)); | ||
90 | NativeAssert::True(pSchema->rgTables[i].rgIndexes != NULL); | ||
91 | } | ||
92 | |||
93 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_KEY].wzName = L"Key"; | ||
94 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_KEY].dbtColumnType = DBTYPE_I4; | ||
95 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_KEY].fPrimaryKey = TRUE; | ||
96 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_KEY].fAutoIncrement = TRUE; | ||
97 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_BINARY].wzName = L"Binary"; | ||
98 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_BINARY].dbtColumnType = DBTYPE_BYTES; | ||
99 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_DWORD].wzName = L"Dword"; | ||
100 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_DWORD].dbtColumnType = DBTYPE_I4; | ||
101 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_QWORD].wzName = L"Qword"; | ||
102 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_QWORD].dbtColumnType = DBTYPE_I8; | ||
103 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_BOOL].wzName = L"Bool"; | ||
104 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_BOOL].dbtColumnType = DBTYPE_BOOL; | ||
105 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_STRING].wzName = L"String"; | ||
106 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_STRING].dbtColumnType = DBTYPE_WSTR; | ||
107 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_DWORD_NULLABLE].wzName = L"Nullable"; | ||
108 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_DWORD_NULLABLE].dbtColumnType = DBTYPE_I4; | ||
109 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_DWORD_NULLABLE].fNullable = TRUE; | ||
110 | |||
111 | if (fIncludeExtended) | ||
112 | { | ||
113 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_EXTRA_STRING].wzName = L"ExtraString"; | ||
114 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_EXTRA_STRING].dbtColumnType = DBTYPE_WSTR; | ||
115 | pSchema->rgTables[TABLE_A].rgColumns[TABLE_A_EXTRA_STRING].fNullable = TRUE; | ||
116 | } | ||
117 | |||
118 | static DWORD rgdwTableA_Index1[] = { TABLE_A_DWORD, TABLE_A_STRING, TABLE_A_QWORD }; | ||
119 | static DWORD rgdwTableA_Index2[] = { TABLE_A_DWORD, TABLE_A_STRING }; | ||
120 | |||
121 | ASSIGN_INDEX_STRUCT(pSchema->rgTables[TABLE_A].rgIndexes[0], rgdwTableA_Index1, L"Dword_String_Qword"); | ||
122 | ASSIGN_INDEX_STRUCT(pSchema->rgTables[TABLE_A].rgIndexes[1], rgdwTableA_Index2, L"Dword_String"); | ||
123 | } | ||
124 | |||
125 | void SetStructValues(TableARowValue *pValue, BYTE *pbBinary, DWORD cBinary, DWORD dw, DWORD64 qw, BOOL f, LPWSTR scz, DWORD *pdw, LPWSTR sczExtra) | ||
126 | { | ||
127 | pValue->pbBinary = pbBinary; | ||
128 | pValue->cBinary = cBinary; | ||
129 | pValue->dw = dw; | ||
130 | pValue->qw = qw; | ||
131 | pValue->f = f; | ||
132 | pValue->scz = scz; | ||
133 | |||
134 | if (pdw) | ||
135 | { | ||
136 | pValue->fNullablePresent = TRUE; | ||
137 | pValue->dwNullable = *pdw; | ||
138 | } | ||
139 | else | ||
140 | { | ||
141 | pValue->fNullablePresent = FALSE; | ||
142 | } | ||
143 | |||
144 | if (sczExtra) | ||
145 | { | ||
146 | pValue->fSchemaV2 = TRUE; | ||
147 | pValue->sczExtra = sczExtra; | ||
148 | } | ||
149 | else | ||
150 | { | ||
151 | pValue->fSchemaV2 = FALSE; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | void AssertStructValuesSame(TableARowValue *pValueExpected, TableARowValue *pValueOther) | ||
156 | { | ||
157 | NativeAssert::Equal(pValueExpected->cBinary, pValueOther->cBinary); | ||
158 | NativeAssert::True(0 == memcmp(pValueExpected->pbBinary, pValueOther->pbBinary, pValueOther->cBinary)); | ||
159 | |||
160 | NativeAssert::Equal(pValueExpected->dw, pValueOther->dw); | ||
161 | NativeAssert::Equal(pValueExpected->qw, pValueOther->qw); | ||
162 | NativeAssert::Equal(pValueExpected->f, pValueOther->f); | ||
163 | NativeAssert::True(0 == wcscmp(pValueExpected->scz, pValueOther->scz)); | ||
164 | |||
165 | NativeAssert::Equal(pValueExpected->fNullablePresent, pValueOther->fNullablePresent); | ||
166 | if (pValueExpected->fNullablePresent) | ||
167 | { | ||
168 | NativeAssert::Equal(pValueExpected->dwNullable, pValueOther->dwNullable); | ||
169 | } | ||
170 | |||
171 | NativeAssert::Equal(pValueExpected->fSchemaV2, pValueOther->fSchemaV2); | ||
172 | if (pValueExpected->fSchemaV2) | ||
173 | { | ||
174 | NativeAssert::True(0 == wcscmp(pValueExpected->sczExtra, pValueOther->sczExtra)); | ||
175 | } | ||
176 | } | ||
177 | |||
178 | void InsertRow(SCE_DATABASE *pDatabase, TableARowValue *pValue, BOOL fRollback) | ||
179 | { | ||
180 | HRESULT hr = S_OK; | ||
181 | SCE_ROW_HANDLE sceRow = NULL; | ||
182 | |||
183 | hr = SceBeginTransaction(pDatabase); | ||
184 | NativeAssert::Succeeded(hr, "Failed to begin transaction"); | ||
185 | |||
186 | hr = ScePrepareInsert(pDatabase, TABLE_A, &sceRow); | ||
187 | NativeAssert::Succeeded(hr, "Failed to prepare to insert row"); | ||
188 | |||
189 | hr = SceSetColumnBinary(sceRow, TABLE_A_BINARY, pValue->pbBinary, pValue->cBinary); | ||
190 | NativeAssert::Succeeded(hr, "Failed to set binary value"); | ||
191 | |||
192 | hr = SceSetColumnDword(sceRow, TABLE_A_DWORD, pValue->dw); | ||
193 | NativeAssert::Succeeded(hr, "Failed to set dword value"); | ||
194 | |||
195 | hr = SceSetColumnQword(sceRow, TABLE_A_QWORD, pValue->qw); | ||
196 | NativeAssert::Succeeded(hr, "Failed to set qword value"); | ||
197 | |||
198 | hr = SceSetColumnBool(sceRow, TABLE_A_BOOL, pValue->f); | ||
199 | NativeAssert::Succeeded(hr, "Failed to set bool value"); | ||
200 | |||
201 | hr = SceSetColumnString(sceRow, TABLE_A_STRING, pValue->scz); | ||
202 | NativeAssert::Succeeded(hr, "Failed to set string value"); | ||
203 | |||
204 | if (pValue->fNullablePresent) | ||
205 | { | ||
206 | hr = SceSetColumnDword(sceRow, TABLE_A_DWORD_NULLABLE, pValue->dwNullable); | ||
207 | NativeAssert::Succeeded(hr, "Failed to set dword value"); | ||
208 | } | ||
209 | else | ||
210 | { | ||
211 | hr = SceSetColumnNull(sceRow, TABLE_A_DWORD_NULLABLE); | ||
212 | NativeAssert::Succeeded(hr, "Failed to set null value"); | ||
213 | } | ||
214 | |||
215 | if (pValue->fSchemaV2) | ||
216 | { | ||
217 | hr = SceSetColumnString(sceRow, TABLE_A_EXTRA_STRING, pValue->sczExtra); | ||
218 | NativeAssert::Succeeded(hr, "Failed to set extra string value"); | ||
219 | } | ||
220 | |||
221 | hr = SceFinishUpdate(sceRow); | ||
222 | NativeAssert::Succeeded(hr, "Failed to finish insert"); | ||
223 | |||
224 | if (fRollback) | ||
225 | { | ||
226 | hr = SceRollbackTransaction(pDatabase); | ||
227 | NativeAssert::Succeeded(hr, "Failed to rollback transaction"); | ||
228 | } | ||
229 | else | ||
230 | { | ||
231 | hr = SceCommitTransaction(pDatabase); | ||
232 | NativeAssert::Succeeded(hr, "Failed to commit transaction"); | ||
233 | |||
234 | hr = SceGetColumnDword(sceRow, TABLE_A_KEY, &pValue->dwAutoGenKey); | ||
235 | NativeAssert::Succeeded(hr, "Failed to get autogen key after insert"); | ||
236 | |||
237 | NativeAssert::True(pValue->dwAutoGenKey != 0); | ||
238 | } | ||
239 | |||
240 | ReleaseSceRow(sceRow); | ||
241 | } | ||
242 | |||
243 | void VerifyRow(TableARowValue *pExpectedValue, SCE_ROW_HANDLE sceRow) | ||
244 | { | ||
245 | HRESULT hr = S_OK; | ||
246 | TableARowValue value = {}; | ||
247 | |||
248 | hr = SceGetColumnBinary(sceRow, TABLE_A_BINARY, &value.pbBinary, &value.cBinary); | ||
249 | NativeAssert::Succeeded(hr, "Failed to get binary value from result row"); | ||
250 | |||
251 | hr = SceGetColumnDword(sceRow, TABLE_A_DWORD, &value.dw); | ||
252 | NativeAssert::Succeeded(hr, "Failed to get dword value from result row"); | ||
253 | |||
254 | hr = SceGetColumnQword(sceRow, TABLE_A_QWORD, &value.qw); | ||
255 | NativeAssert::Succeeded(hr, "Failed to get qword value from result row"); | ||
256 | |||
257 | hr = SceGetColumnBool(sceRow, TABLE_A_BOOL, &value.f); | ||
258 | NativeAssert::Succeeded(hr, "Failed to get bool value from result row"); | ||
259 | |||
260 | hr = SceGetColumnString(sceRow, TABLE_A_STRING, &value.scz); | ||
261 | NativeAssert::Succeeded(hr, "Failed to get string value from result row"); | ||
262 | |||
263 | hr = SceGetColumnDword(sceRow, TABLE_A_DWORD_NULLABLE, &value.dwNullable); | ||
264 | if (hr == E_NOTFOUND) | ||
265 | { | ||
266 | value.fNullablePresent = FALSE; | ||
267 | hr = S_OK; | ||
268 | } | ||
269 | else | ||
270 | { | ||
271 | NativeAssert::Succeeded(hr, "Failed to get string value from result row"); | ||
272 | value.fNullablePresent = TRUE; | ||
273 | } | ||
274 | |||
275 | if (pExpectedValue->fSchemaV2) | ||
276 | { | ||
277 | value.fSchemaV2 = TRUE; | ||
278 | hr = SceGetColumnString(sceRow, TABLE_A_EXTRA_STRING, &value.sczExtra); | ||
279 | NativeAssert::Succeeded(hr, "Failed to get extra string value from result row"); | ||
280 | } | ||
281 | |||
282 | AssertStructValuesSame(pExpectedValue, &value); | ||
283 | |||
284 | ReleaseNullMem(value.pbBinary); | ||
285 | ReleaseNullStr(value.scz); | ||
286 | } | ||
287 | |||
288 | void VerifyQuery(TableARowValue **rgExpectedValues, DWORD cExpectedValues, SCE_QUERY_RESULTS_HANDLE queryResults) | ||
289 | { | ||
290 | HRESULT hr = S_OK; | ||
291 | SCE_ROW_HANDLE sceRow = NULL; | ||
292 | |||
293 | for (DWORD i = 0; i < cExpectedValues; ++i) | ||
294 | { | ||
295 | hr = SceGetNextResultRow(queryResults, &sceRow); | ||
296 | NativeAssert::Succeeded(hr, "Failed to get next result row"); | ||
297 | |||
298 | VerifyRow(rgExpectedValues[i], sceRow); | ||
299 | ReleaseNullSceRow(sceRow); | ||
300 | } | ||
301 | |||
302 | // No more results | ||
303 | NativeAssert::True(NULL == queryResults || FAILED(SceGetNextResultRow(queryResults, &sceRow))); | ||
304 | } | ||
305 | |||
306 | void TestIndex(SCE_DATABASE *pDatabase) | ||
307 | { | ||
308 | HRESULT hr = S_OK; | ||
309 | BYTE binary1[50] = { 0x80, 0x70 }; | ||
310 | BYTE binary2[40] = { 0x90, 0xAB }; | ||
311 | BYTE binary3[40] = { 0x85, 0x88 }; | ||
312 | DWORD dwValue1 = 0x55555555, dwValue2 = 0x88888888; | ||
313 | TableARowValue value1 = {}, value2 = {}, value3 = {}, value4 = {}, value5 = {}; | ||
314 | SCE_QUERY_HANDLE query = NULL; | ||
315 | SCE_QUERY_RESULTS_HANDLE results = NULL; | ||
316 | |||
317 | SetStructValues(&value1, static_cast<BYTE *>(binary1), sizeof(binary1), 3, 1, TRUE, L"zzz", &dwValue1, NULL); | ||
318 | SetStructValues(&value2, static_cast<BYTE *>(binary2), sizeof(binary2), 3, 2, TRUE, L"yyy", &dwValue2, NULL); | ||
319 | SetStructValues(&value3, static_cast<BYTE *>(binary3), sizeof(binary3), 3, 3, TRUE, L"xxx", NULL, NULL); | ||
320 | SetStructValues(&value4, static_cast<BYTE *>(binary2), sizeof(binary2), 4, 4, TRUE, L"xyz", &dwValue2, NULL); | ||
321 | SetStructValues(&value5, static_cast<BYTE *>(binary3), sizeof(binary3), 3, 1, TRUE, L"yyy", &dwValue2, NULL); | ||
322 | |||
323 | // Rollback an insert to confirm the insert doesn't happen and database can still be interacted with normally afterwards | ||
324 | InsertRow(pDatabase, &value1, TRUE); | ||
325 | |||
326 | InsertRow(pDatabase, &value1, FALSE); | ||
327 | InsertRow(pDatabase, &value2, FALSE); | ||
328 | InsertRow(pDatabase, &value3, FALSE); | ||
329 | InsertRow(pDatabase, &value4, FALSE); | ||
330 | InsertRow(pDatabase, &value5, FALSE); | ||
331 | |||
332 | NativeAssert::True(value1.dwAutoGenKey != value2.dwAutoGenKey); | ||
333 | |||
334 | // Test setting 1 column | ||
335 | hr = SceBeginQuery(pDatabase, TABLE_A, 0, &query); | ||
336 | NativeAssert::Succeeded(hr, "Failed to begin query"); | ||
337 | |||
338 | hr = SceSetQueryColumnDword(query, 3); | ||
339 | NativeAssert::Succeeded(hr, "Failed to set query column dword"); | ||
340 | |||
341 | hr = SceRunQueryRange(&query, &results); | ||
342 | NativeAssert::Succeeded(hr, "Failed to run query"); | ||
343 | NativeAssert::True(query == NULL); | ||
344 | |||
345 | TableARowValue *sortedAfterQuery1[] = { &value3, &value5, &value2, &value1 }; | ||
346 | VerifyQuery(sortedAfterQuery1, _countof(sortedAfterQuery1), results); | ||
347 | ReleaseNullSceQueryResults(results); | ||
348 | |||
349 | // Test setting 2 columns, third column is unspecified so results are sorted by it | ||
350 | hr = SceBeginQuery(pDatabase, TABLE_A, 0, &query); | ||
351 | NativeAssert::Succeeded(hr, "Failed to begin query"); | ||
352 | |||
353 | hr = SceSetQueryColumnDword(query, 3); | ||
354 | NativeAssert::Succeeded(hr, "Failed to set query column dword"); | ||
355 | |||
356 | hr = SceSetQueryColumnString(query, L"yyy"); | ||
357 | NativeAssert::Succeeded(hr, "Failed to set query column dword"); | ||
358 | |||
359 | hr = SceRunQueryRange(&query, &results); | ||
360 | NativeAssert::Succeeded(hr, "Failed to run query"); | ||
361 | NativeAssert::True(query == NULL); | ||
362 | |||
363 | TableARowValue *sortedAfterQuery2[] = { &value5, &value2 }; | ||
364 | VerifyQuery(sortedAfterQuery2, _countof(sortedAfterQuery2), results); | ||
365 | ReleaseNullSceQueryResults(results); | ||
366 | |||
367 | // Test setting 2 columns, third column of index is unspecified so results are sorted by it | ||
368 | hr = SceBeginQuery(pDatabase, TABLE_A, 0, &query); | ||
369 | NativeAssert::Succeeded(hr, "Failed to begin query"); | ||
370 | |||
371 | hr = SceSetQueryColumnDword(query, 3); | ||
372 | NativeAssert::Succeeded(hr, "Failed to set query column dword"); | ||
373 | |||
374 | hr = SceSetQueryColumnString(query, L"yyy"); | ||
375 | NativeAssert::Succeeded(hr, "Failed to set query column dword"); | ||
376 | |||
377 | hr = SceRunQueryRange(&query, &results); | ||
378 | NativeAssert::Succeeded(hr, "Failed to run query"); | ||
379 | NativeAssert::True(query == NULL); | ||
380 | |||
381 | TableARowValue *sortedAfterQuery3[] = { &value5, &value2 }; | ||
382 | VerifyQuery(sortedAfterQuery3, _countof(sortedAfterQuery3), results); | ||
383 | ReleaseNullSceQueryResults(results); | ||
384 | |||
385 | // Test setting 2 columns in a different (2 column) index, so there is no 3rd column in index to sort by | ||
386 | hr = SceBeginQuery(pDatabase, TABLE_A, 1, &query); | ||
387 | NativeAssert::Succeeded(hr, "Failed to begin query"); | ||
388 | |||
389 | hr = SceSetQueryColumnDword(query, 3); | ||
390 | NativeAssert::Succeeded(hr, "Failed to set query column dword"); | ||
391 | |||
392 | hr = SceSetQueryColumnString(query, L"yyy"); | ||
393 | NativeAssert::Succeeded(hr, "Failed to set query column dword"); | ||
394 | |||
395 | hr = SceRunQueryRange(&query, &results); | ||
396 | NativeAssert::Succeeded(hr, "Failed to run query"); | ||
397 | NativeAssert::True(query == NULL); | ||
398 | |||
399 | TableARowValue *sortedAfterQuery4[] = { &value2, &value5 }; | ||
400 | VerifyQuery(sortedAfterQuery4, _countof(sortedAfterQuery4), results); | ||
401 | ReleaseNullSceQueryResults(results); | ||
402 | } | ||
403 | |||
404 | void TestReadWriteSchemaV2(SCE_DATABASE *pDatabase) | ||
405 | { | ||
406 | HRESULT hr = S_OK; | ||
407 | BYTE binary1[40] = { 0x55, 0x44 }; | ||
408 | DWORD dwValue1 = 58; | ||
409 | TableARowValue value1 = {}; | ||
410 | SCE_QUERY_HANDLE query = NULL; | ||
411 | SCE_ROW_HANDLE row = NULL; | ||
412 | |||
413 | SetStructValues(&value1, static_cast<BYTE *>(binary1), sizeof(binary1), 5, 1, TRUE, L"zzz", &dwValue1, L"newextrastring"); | ||
414 | |||
415 | InsertRow(pDatabase, &value1, FALSE); | ||
416 | |||
417 | // Test setting 1 column | ||
418 | hr = SceBeginQuery(pDatabase, TABLE_A, 0, &query); | ||
419 | NativeAssert::Succeeded(hr, "Failed to begin query"); | ||
420 | |||
421 | hr = SceSetQueryColumnDword(query, 5); | ||
422 | NativeAssert::Succeeded(hr, "Failed to set query column dword"); | ||
423 | |||
424 | hr = SceRunQueryExact(&query, &row); | ||
425 | NativeAssert::Succeeded(hr, "Failed to run query exact"); | ||
426 | |||
427 | VerifyRow(&value1, row); | ||
428 | } | ||
429 | |||
430 | [Fact] | ||
431 | void SceUtilTest() | ||
432 | { | ||
433 | HRESULT hr = S_OK; | ||
434 | BOOL fComInitialized = FALSE; | ||
435 | LPWSTR sczDbPath = NULL; | ||
436 | SCE_DATABASE *pDatabase = NULL; | ||
437 | SCE_DATABASE_SCHEMA schema1 = {}; | ||
438 | SCE_DATABASE_SCHEMA schema2 = {}; | ||
439 | |||
440 | try | ||
441 | { | ||
442 | hr = ::CoInitialize(0); | ||
443 | NativeAssert::Succeeded(hr, "Failed to initialize COM"); | ||
444 | fComInitialized = TRUE; | ||
445 | |||
446 | SetupSchema(&schema1, FALSE); | ||
447 | SetupSchema(&schema2, TRUE); | ||
448 | |||
449 | hr = PathExpand(&sczDbPath, L"%TEMP%\\SceUtilTest\\UnitTest.sdf", PATH_EXPAND_ENVIRONMENT); | ||
450 | NativeAssert::Succeeded(hr, "Failed to get path to test database"); | ||
451 | |||
452 | FileEnsureDelete(sczDbPath); | ||
453 | |||
454 | hr = SceEnsureDatabase(sczDbPath, L"sqlceoledb40.dll", L"Test", 1, &schema1, &pDatabase); | ||
455 | NativeAssert::Succeeded(hr, "Failed to ensure database schema"); | ||
456 | |||
457 | TestIndex(pDatabase); | ||
458 | |||
459 | hr = SceCloseDatabase(pDatabase); | ||
460 | pDatabase = NULL; | ||
461 | NativeAssert::Succeeded(hr, "Failed to close database"); | ||
462 | |||
463 | // Add column to schema | ||
464 | hr = SceEnsureDatabase(sczDbPath, L"sqlceoledb40.dll", L"Test", 1, &schema2, &pDatabase); | ||
465 | NativeAssert::Succeeded(hr, "Failed to ensure database schema"); | ||
466 | |||
467 | TestReadWriteSchemaV2(pDatabase); | ||
468 | } | ||
469 | finally | ||
470 | { | ||
471 | ReleaseSceSchema(&schema1); | ||
472 | ReleaseSceSchema(&schema2); | ||
473 | |||
474 | if (NULL != pDatabase) | ||
475 | { | ||
476 | hr = SceCloseDatabase(pDatabase); | ||
477 | NativeAssert::Succeeded(hr, "Failed to close database"); | ||
478 | } | ||
479 | ReleaseStr(sczDbPath); | ||
480 | |||
481 | if (fComInitialized) | ||
482 | { | ||
483 | ::CoUninitialize(); | ||
484 | } | ||
485 | } | ||
486 | } | ||
487 | }; | ||
488 | } | ||