1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite RtlGenericTable
5  * PROGRAMMER:      arty
6  */
7 
8 #define KMT_EMULATE_KERNEL
9 #include <kmt_test.h>
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 static LIST_ENTRY Allocations;
15 
16 static RTL_GENERIC_COMPARE_RESULTS NTAPI
17 CompareCharTable(PRTL_GENERIC_TABLE Table, PVOID A, PVOID B)
18 {
19     RTL_GENERIC_COMPARE_RESULTS Result = (*((PCHAR)A) < *((PCHAR)B)) ? GenericLessThan :
20         (*((PCHAR)A) > *((PCHAR)B)) ? GenericGreaterThan :
21         GenericEqual;
22     return Result;
23 }
24 
25 static PVOID NTAPI
26 AllocRoutine(PRTL_GENERIC_TABLE Table, CLONG ByteSize)
27 {
28     PLIST_ENTRY Entry = ExAllocatePool
29         (NonPagedPool, sizeof(LIST_ENTRY) + ByteSize);
30     InsertTailList(&Allocations, Entry);
31     return &Entry[1];
32 }
33 
34 static VOID NTAPI
35 FreeRoutine(PRTL_GENERIC_TABLE Table, PVOID Buffer)
36 {
37     PLIST_ENTRY Entry = (PLIST_ENTRY)(((PCHAR)Buffer) - sizeof(LIST_ENTRY));
38     RemoveEntryList(Entry);
39     ExFreePool(Entry);
40 }
41 
42 static void RtlSplayTreeTest()
43 {
44     ULONG i, del;
45     PCHAR Ch;
46     CHAR Text[] = "the quick_brown!fOx-jUmp3d/0vER+THe^lazy.D@g";
47     CHAR NewE[] = "11111111111111111111111111111111110111111111";
48     RTL_GENERIC_TABLE Table;
49     RtlInitializeGenericTable
50         (&Table,
51          CompareCharTable,
52          AllocRoutine,
53          FreeRoutine,
54          NULL);
55     for (i = 0; Text[i]; i++) {
56         BOOLEAN WasNew;
57         Ch = (PCHAR)RtlInsertElementGenericTable
58             (&Table,
59              &Text[i],
60              sizeof(Text[i]),
61              &WasNew);
62         ok(Ch && *Ch == Text[i], "Copy character into node\n");
63         ok(WasNew == (NewE[i] == '1'),
64            "Character newness didn't match for char %u: '%c'\n",
65            i, Text[i]);
66     }
67     for (Ch = (PCHAR)RtlEnumerateGenericTable(&Table, TRUE), i = 0;
68          Ch;
69          Ch = (PCHAR)RtlEnumerateGenericTable(&Table, FALSE), i++) {
70         ok(strchr(Text, *Ch) != NULL, "Nonexistent character\n");
71     }
72     ok(RtlNumberGenericTableElements(&Table) == strlen(Text) - 1, "Not the right number of elements\n");
73     ok(RtlLookupElementGenericTable(&Table, "q") != NULL, "Could not lookup q\n");
74     ok(!RtlLookupElementGenericTable(&Table, "#"), "Found a character that shouldn't appear\n");
75     ok(strlen(Text) == i + 1, "Didn't enumerate enough characters\n");
76     del = 0;
77     for (i = 0; Text[i]; i++) {
78         if (NewE[i] == '1') {
79             BOOLEAN WasDeleted;
80             WasDeleted = RtlDeleteElementGenericTable(&Table, &Text[i]);
81             del += WasDeleted;
82         }
83     }
84     ok(!RtlNumberGenericTableElements(&Table), "Not zero elements\n");
85     ok(!RtlGetElementGenericTable(&Table, 0), "Elements left when we removed them all\n");
86     ok(strlen(Text) == del + 1, "Deleted too many times\n");
87     ok(IsListEmpty(&Allocations), "Didn't free all memory\n");
88 }
89 
90 START_TEST(RtlSplayTree)
91 {
92     InitializeListHead(&Allocations);
93     RtlSplayTreeTest();
94 }
95