1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite Runtime library unicode string functions test
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #define KMT_EMULATE_KERNEL
9 #include <kmt_test.h>
10 
11 static
12 VOID
13 TestFindCharInUnicodeString(VOID)
14 {
15 #ifdef KMT_USER_MODE
16     NTSTATUS Status;
17     UNICODE_STRING String = RTL_CONSTANT_STRING(L"I am a string");
18     UNICODE_STRING Chars = RTL_CONSTANT_STRING(L"a");
19     UNICODE_STRING Chars2 = RTL_CONSTANT_STRING(L"A");
20     UNICODE_STRING Chars3 = RTL_CONSTANT_STRING(L"i");
21     UNICODE_STRING Chars4 = RTL_CONSTANT_STRING(L"G");
22     UNICODE_STRING ZeroLengthString;
23     USHORT Position;
24     ULONG LongPosition;
25 
26     RtlInitUnicodeString(&ZeroLengthString, NULL);
27 
28     /* Basic checks. Covered by Winetests */
29     Position = 123;
30     Status = RtlFindCharInUnicodeString(0, &String, &Chars, &Position);
31     ok_eq_hex(Status, STATUS_SUCCESS);
32     ok_eq_uint(Position, 6);
33 
34     Position = 123;
35     Status = RtlFindCharInUnicodeString(1, &String, &Chars, &Position);
36     ok_eq_hex(Status, STATUS_SUCCESS);
37     ok_eq_uint(Position, 10);
38 
39     Position = 123;
40     Status = RtlFindCharInUnicodeString(2, &String, &Chars, &Position);
41     ok_eq_hex(Status, STATUS_SUCCESS);
42     ok_eq_uint(Position, 2);
43 
44     Position = 123;
45     Status = RtlFindCharInUnicodeString(3, &String, &Chars, &Position);
46     ok_eq_hex(Status, STATUS_SUCCESS);
47     ok_eq_uint(Position, 24);
48 
49     /* Show that checks are case sensitive by default */
50     Position = 123;
51     Status = RtlFindCharInUnicodeString(0, &String, &Chars2, &Position);
52     ok_eq_hex(Status, STATUS_NOT_FOUND);
53     ok_eq_uint(Position, 0);
54 
55     Position = 123;
56     Status = RtlFindCharInUnicodeString(1, &String, &Chars2, &Position);
57     ok_eq_hex(Status, STATUS_NOT_FOUND);
58     ok_eq_uint(Position, 0);
59 
60     Position = 123;
61     Status = RtlFindCharInUnicodeString(2, &String, &Chars3, &Position);
62     ok_eq_hex(Status, STATUS_SUCCESS);
63     ok_eq_uint(Position, 2);
64 
65     Position = 123;
66     Status = RtlFindCharInUnicodeString(3, &String, &Chars4, &Position);
67     ok_eq_hex(Status, STATUS_SUCCESS);
68     ok_eq_uint(Position, 24);
69 
70     /* Show that 4 means case insensitive */
71     Position = 123;
72     Status = RtlFindCharInUnicodeString(4, &String, &Chars2, &Position);
73     ok_eq_hex(Status, STATUS_SUCCESS);
74     ok_eq_uint(Position, 6);
75 
76     Position = 123;
77     Status = RtlFindCharInUnicodeString(5, &String, &Chars2, &Position);
78     ok_eq_hex(Status, STATUS_SUCCESS);
79     ok_eq_uint(Position, 10);
80 
81     Position = 123;
82     Status = RtlFindCharInUnicodeString(6, &String, &Chars3, &Position);
83     ok_eq_hex(Status, STATUS_SUCCESS);
84     ok_eq_uint(Position, 4);
85 
86     Position = 123;
87     Status = RtlFindCharInUnicodeString(7, &String, &Chars4, &Position);
88     ok_eq_hex(Status, STATUS_SUCCESS);
89     ok_eq_uint(Position, 22);
90 
91     /* Show that Position is USHORT */
92     LongPosition = 0x55555555;
93     Status = RtlFindCharInUnicodeString(8, &String, &String, (PUSHORT)&LongPosition);
94     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
95     ok_eq_ulong(LongPosition, 0x55550000UL);
96 
97     /* Invalid flags */
98     Position = 123;
99     Status = RtlFindCharInUnicodeString(8, &String, &String, &Position);
100     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
101     ok_eq_uint(Position, 0);
102 
103     Position = 123;
104     Status = RtlFindCharInUnicodeString(0xFFFFFFF8, &String, &String, &Position);
105     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
106     ok_eq_uint(Position, 0);
107 
108     Position = 123;
109     Status = RtlFindCharInUnicodeString(0xFFFFFFFF, &String, &String, &Position);
110     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
111     ok_eq_uint(Position, 0);
112 
113     /* NULL for SearchString */
114     Position = 123;
115     KmtStartSeh()
116         Status = RtlFindCharInUnicodeString(0, NULL, &String, &Position);
117     KmtEndSeh(STATUS_ACCESS_VIOLATION);
118     ok_eq_uint(Position, 0);
119 
120     /* NULL for SearchString and invalid flags */
121     Position = 123;
122     KmtStartSeh()
123         Status = RtlFindCharInUnicodeString(8, NULL, &String, &Position);
124     KmtEndSeh(STATUS_SUCCESS);
125     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
126     ok_eq_uint(Position, 0);
127     ok_eq_uint(Position, 0);
128 
129     /* NULL for SearchString with zero-length MatchString */
130     Position = 123;
131     KmtStartSeh()
132         Status = RtlFindCharInUnicodeString(0, NULL, &ZeroLengthString, &Position);
133     KmtEndSeh(STATUS_ACCESS_VIOLATION);
134     ok_eq_uint(Position, 0);
135 
136     /* NULL for MatchString */
137     Position = 123;
138     KmtStartSeh()
139         Status = RtlFindCharInUnicodeString(0, &String, NULL, &Position);
140     KmtEndSeh(STATUS_ACCESS_VIOLATION);
141     ok_eq_uint(Position, 0);
142 
143     /* This crashes in Windows, but not in ROS. I see no reason to add
144      * additional code or redesign the function to replicate that */
145 #if 0
146     /* NULL for MatchString with zero-length SearchString */
147     Position = 123;
148     KmtStartSeh()
149         Status = RtlFindCharInUnicodeString(0, &ZeroLengthString, NULL, &Position);
150     KmtEndSeh(STATUS_ACCESS_VIOLATION);
151     ok_eq_uint(Position, 0);
152 #endif
153 
154     /* NULL for MatchString and invalid flags */
155     Position = 123;
156     KmtStartSeh()
157         Status = RtlFindCharInUnicodeString(8, &String, NULL, &Position);
158     KmtEndSeh(STATUS_SUCCESS);
159     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
160     ok_eq_uint(Position, 0);
161 
162     /* NULL for Position */
163     KmtStartSeh()
164         Status = RtlFindCharInUnicodeString(0, &String, &String, NULL);
165     KmtEndSeh(STATUS_SUCCESS);
166     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
167 
168     /* NULL for all three */
169     KmtStartSeh()
170         Status = RtlFindCharInUnicodeString(0, NULL, NULL, NULL);
171     KmtEndSeh(STATUS_SUCCESS);
172     ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
173 #endif
174 }
175 
176 static
177 VOID
178 TestUpcaseUnicodeString(VOID)
179 {
180     NTSTATUS Status;
181     UNICODE_STRING Lower;
182     UNICODE_STRING Upper;
183     PWCHAR Buffer;
184 
185     Buffer = KmtAllocateGuarded(sizeof(WCHAR));
186 
187     if (!KmtIsCheckedBuild)
188     {
189     RtlInitEmptyUnicodeString(&Lower, NULL, 0);
190     RtlFillMemory(&Upper, sizeof(Upper), 0x55);
191     Status = RtlUpcaseUnicodeString(&Upper, &Lower, TRUE);
192     ok_eq_hex(Status, STATUS_SUCCESS);
193     ok_eq_uint(Upper.Length, 0);
194     ok_eq_uint(Upper.MaximumLength, 0);
195     ok(Upper.Buffer != NULL, "Buffer = %p\n", Upper.Buffer);
196     RtlFreeUnicodeString(&Upper);
197 
198     RtlInitEmptyUnicodeString(&Lower, Buffer, 0);
199     RtlFillMemory(&Upper, sizeof(Upper), 0x55);
200     Status = RtlUpcaseUnicodeString(&Upper, &Lower, TRUE);
201     ok_eq_hex(Status, STATUS_SUCCESS);
202     ok_eq_uint(Upper.Length, 0);
203     ok_eq_uint(Upper.MaximumLength, 0);
204     ok(Upper.Buffer != NULL, "Buffer = %p\n", Upper.Buffer);
205     RtlFreeUnicodeString(&Upper);
206 
207     RtlInitEmptyUnicodeString(&Lower, Buffer, sizeof(WCHAR));
208     Buffer[0] = UNICODE_NULL;
209     RtlFillMemory(&Upper, sizeof(Upper), 0x55);
210     Status = RtlUpcaseUnicodeString(&Upper, &Lower, TRUE);
211     ok_eq_hex(Status, STATUS_SUCCESS);
212     ok_eq_uint(Upper.Length, 0);
213     ok_eq_uint(Upper.MaximumLength, 0);
214     ok(Upper.Buffer != NULL, "Buffer = %p\n", Upper.Buffer);
215     RtlFreeUnicodeString(&Upper);
216     }
217 
218     RtlInitEmptyUnicodeString(&Lower, Buffer, sizeof(WCHAR));
219     Lower.Length = sizeof(WCHAR);
220     Buffer[0] = UNICODE_NULL;
221     RtlFillMemory(&Upper, sizeof(Upper), 0x55);
222     Status = RtlUpcaseUnicodeString(&Upper, &Lower, TRUE);
223     ok_eq_hex(Status, STATUS_SUCCESS);
224     ok_eq_uint(Upper.Length, sizeof(WCHAR));
225     ok_eq_uint(Upper.MaximumLength, sizeof(WCHAR));
226     ok(Upper.Buffer != NULL, "Buffer = %p\n", Upper.Buffer);
227     ok_eq_hex(Upper.Buffer[0], UNICODE_NULL);
228     RtlFreeUnicodeString(&Upper);
229 
230     RtlInitEmptyUnicodeString(&Lower, Buffer, sizeof(WCHAR));
231     Lower.Length = sizeof(WCHAR);
232     Buffer[0] = 'a';
233     RtlFillMemory(&Upper, sizeof(Upper), 0x55);
234     Status = RtlUpcaseUnicodeString(&Upper, &Lower, TRUE);
235     ok_eq_hex(Status, STATUS_SUCCESS);
236     ok_eq_uint(Upper.Length, sizeof(WCHAR));
237     ok_eq_uint(Upper.MaximumLength, sizeof(WCHAR));
238     ok(Upper.Buffer != NULL, "Buffer = %p\n", Upper.Buffer);
239     ok_eq_hex(Upper.Buffer[0], 'A');
240     RtlFreeUnicodeString(&Upper);
241 
242     RtlInitUnicodeString(&Lower, L"a");
243     RtlFillMemory(&Upper, sizeof(Upper), 0x55);
244     Status = RtlUpcaseUnicodeString(&Upper, &Lower, TRUE);
245     ok_eq_hex(Status, STATUS_SUCCESS);
246     ok_eq_uint(Upper.Length, sizeof(WCHAR));
247     ok_eq_uint(Upper.MaximumLength, sizeof(WCHAR));
248     ok(Upper.Buffer != NULL, "Buffer = %p\n", Upper.Buffer);
249     ok_eq_hex(Upper.Buffer[0], 'A');
250     RtlFreeUnicodeString(&Upper);
251 
252     KmtFreeGuarded(Buffer);
253 }
254 
255 START_TEST(RtlUnicodeString)
256 {
257     TestFindCharInUnicodeString();
258     TestUpcaseUnicodeString();
259 }
260