From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/ntdll/tests/rtl.c | 84 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)
diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index a08b021add7..325a4a13b11 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -92,6 +92,7 @@ static HMODULE hntdll = 0; static PRTL_SPLAY_LINKS (WINAPI *pRtlDelete)(PRTL_SPLAY_LINKS); static void (WINAPI *pRtlDeleteNoSplay)(PRTL_SPLAY_LINKS, PRTL_SPLAY_LINKS *); static BOOLEAN (WINAPI *pRtlDeleteElementGenericTable)(PRTL_GENERIC_TABLE,PVOID); +static void * (WINAPI *pRtlEnumerateGenericTable)(PRTL_GENERIC_TABLE, BOOLEAN); static void * (WINAPI *pRtlEnumerateGenericTableWithoutSplaying)(PRTL_GENERIC_TABLE, PVOID *); static VOID (WINAPI *pRtlMoveMemory)(LPVOID,LPCVOID,SIZE_T); static VOID (WINAPI *pRtlFillMemory)(LPVOID,SIZE_T,BYTE); @@ -162,6 +163,7 @@ static void InitFunctionPtrs(void) pRtlDelete = (void *)GetProcAddress(hntdll, "RtlDelete"); pRtlDeleteElementGenericTable = (void *)GetProcAddress(hntdll, "RtlDeleteElementGenericTable"); pRtlDeleteNoSplay = (void *)GetProcAddress(hntdll, "RtlDeleteNoSplay"); + pRtlEnumerateGenericTable = (void *)GetProcAddress(hntdll, "RtlEnumerateGenericTable"); pRtlEnumerateGenericTableWithoutSplaying = (void *)GetProcAddress(hntdll, "RtlEnumerateGenericTableWithoutSplaying"); pRtlMoveMemory = (void *)GetProcAddress(hntdll, "RtlMoveMemory"); pRtlFillMemory = (void *)GetProcAddress(hntdll, "RtlFillMemory"); @@ -5216,6 +5218,87 @@ static void test_RtlEnumerateGenericTableWithoutSplaying(void) } }
+static void test_RtlEnumerateGenericTable(void) +{ + static const int elements[] = {1, 9, 5, 4, 7, 2, 3, 8, 6}; + static const int expected_elements[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + int i, j, value, *ret, *first_ret = NULL, *last_ret = NULL; + BOOLEAN success, new_element; + RTL_GENERIC_TABLE table; + LIST_ENTRY *entry; + + if (!pRtlEnumerateGenericTable) + { + win_skip("RtlEnumerateGenericTable is unavailable.\n"); + return; + } + + pRtlInitializeGenericTable(&table, generic_compare_proc, generic_allocate_proc, generic_free_proc, NULL); + + ret = pRtlEnumerateGenericTable(&table, TRUE); + ok(!ret, "Got unexpected pointer.\n"); + + ret = pRtlEnumerateGenericTable(&table, FALSE); + ok(!ret, "Got unexpected pointer.\n"); + + for (i = 0; i < ARRAY_SIZE(elements); i++) + { + value = elements[i]; + ret = pRtlInsertElementGenericTable(&table, &value, sizeof(value), &new_element); + ok(ret && *ret == value, "Got unexpected pointer.\n"); + ok(new_element, "Expected new element.\n"); + + if (i == 0) + first_ret = ret; + if (i == ARRAY_SIZE(elements) - 1) + last_ret = ret; + } + + /* Test enumeration */ + for (i = 0, ret = pRtlEnumerateGenericTable(&table, TRUE); ret != NULL; + ret = pRtlEnumerateGenericTable(&table, FALSE), i++) + { + ok(ret && *ret == expected_elements[i], "Expected %d at %d, got %d.\n", + expected_elements[i], i, ret ? *ret : -1); + ok(table.TableRoot == get_splay_links_from_data(ret), "Got unexpected TableRoot.\n"); + + /* Test that RtlEnumerateGenericTable() doesn't touch WhichOrderedElement, OrderedPointer and + * InsertOrderList. Additional tests show that RtlEnumerateGenericTable() uses TableRoot + * to keep track of enumeration status. This also means that if other functions that change + * TableRoot get used during enumerations, RtlEnumerateGenericTable() won't be able to find + * the correct next element, which is also the case on Windows */ + ok(table.WhichOrderedElement == 0, "Got unexpected WhichOrderedElement.\n"); + ok(table.OrderedPointer == &table.InsertOrderList, "Got unexpected OrderedPointer.\n"); + ok(table.InsertOrderList.Flink == get_list_entry_from_data(first_ret), "Got unexpected Flink.\n"); + ok(table.InsertOrderList.Blink == get_list_entry_from_data(last_ret), "Got unexpected Blink.\n"); + for (j = 0, entry = table.InsertOrderList.Flink; entry->Flink != table.InsertOrderList.Flink; + j++, entry = entry->Flink) + { + ret = (int *)get_data_from_list_entry(entry); + ok(*ret == elements[j], "Got unexpected pointer, value %d.\n", *ret); + } + ok(table.TableContext == NULL, "Got unexpected TableContext.\n"); + } + ok(i == ARRAY_SIZE(elements), "Got unexpected index %d.\n", i); + + /* Test restarting enumeration */ + for (i = 0, ret = pRtlEnumerateGenericTable(&table, TRUE); ret != NULL; + ret = pRtlEnumerateGenericTable(&table, FALSE), i++) + { + ok(ret && *ret == expected_elements[i], "Expected %d at %d, got %d.\n", expected_elements[i], + i, ret ? *ret : -1); + ok(table.TableRoot == get_splay_links_from_data(ret), "Got unexpected TableRoot.\n"); + } + ok(i == ARRAY_SIZE(elements), "Got unexpected index %d.\n", i); + + for (i = 0; i < ARRAY_SIZE(elements); i++) + { + value = elements[i]; + success = pRtlDeleteElementGenericTable(&table, &value); + ok(success, "RtlDeleteElementGenericTable failed.\n"); + } +} + START_TEST(rtl) { InitFunctionPtrs(); @@ -5282,4 +5365,5 @@ START_TEST(rtl) test_RtlDeleteElementGenericTable(); test_RtlLookupElementGenericTable(); test_RtlEnumerateGenericTableWithoutSplaying(); + test_RtlEnumerateGenericTable(); }