diff options
| author | Rob Mensching <rob@firegiant.com> | 2021-04-22 06:38:23 -0700 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2021-04-29 16:21:09 -0700 |
| commit | 7f642e51670bc38a4ef782a363936850bc2b0ba9 (patch) | |
| tree | 19684b2d94979f130c0935328f0d44cf006e45ef /src/libs/dutil/test/DUtilUnitTest/SceUtilTest.cpp | |
| parent | f39e7a3e164d0736e45049e5726d0da2013da3c9 (diff) | |
| download | wix-7f642e51670bc38a4ef782a363936850bc2b0ba9.tar.gz wix-7f642e51670bc38a4ef782a363936850bc2b0ba9.tar.bz2 wix-7f642e51670bc38a4ef782a363936850bc2b0ba9.zip | |
Move dutil into libs/dutil
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 | } | ||
