diff --git a/rostests/kmtests/CMakeLists.txt b/rostests/kmtests/CMakeLists.txt
index 8011065e025..92d092df443 100644
--- a/rostests/kmtests/CMakeLists.txt
+++ b/rostests/kmtests/CMakeLists.txt
@@ -11,7 +11,8 @@ list(APPEND COMMON_SOURCE
example/GuardedMemory.c
rtl/RtlAvlTree.c
rtl/RtlMemory.c
- rtl/RtlSplayTree.c)
+ rtl/RtlSplayTree.c
+ rtl/RtlUnicodeString.c)
#
# kmtest_drv.sys driver
diff --git a/rostests/kmtests/kmtest.rbuild b/rostests/kmtests/kmtest.rbuild
index 62849808d59..306261cde8b 100644
--- a/rostests/kmtests/kmtest.rbuild
+++ b/rostests/kmtests/kmtest.rbuild
@@ -21,5 +21,6 @@
RtlAvlTree.c
RtlMemory.c
RtlSplayTree.c
+ RtlUnicodeString.c
diff --git a/rostests/kmtests/kmtest/testlist.c b/rostests/kmtests/kmtest/testlist.c
index ad017c0578e..117404f4d48 100644
--- a/rostests/kmtests/kmtest/testlist.c
+++ b/rostests/kmtests/kmtest/testlist.c
@@ -12,6 +12,7 @@ KMT_TESTFUNC Test_IoDeviceObject;
KMT_TESTFUNC Test_RtlAvlTree;
KMT_TESTFUNC Test_RtlMemory;
KMT_TESTFUNC Test_RtlSplayTree;
+KMT_TESTFUNC Test_RtlUnicodeString;
/* tests with a leading '-' will not be listed */
const KMT_TEST TestList[] =
@@ -21,5 +22,6 @@ const KMT_TEST TestList[] =
{ "RtlAvlTree", Test_RtlAvlTree },
{ "RtlMemory", Test_RtlMemory },
{ "RtlSplayTree", Test_RtlSplayTree },
+ { "RtlUnicodeString", Test_RtlUnicodeString },
{ NULL, NULL },
};
diff --git a/rostests/kmtests/kmtest_drv.rbuild b/rostests/kmtests/kmtest_drv.rbuild
index 624b1b5e816..af34b02afec 100644
--- a/rostests/kmtests/kmtest_drv.rbuild
+++ b/rostests/kmtests/kmtest_drv.rbuild
@@ -56,6 +56,7 @@
RtlAvlTree.c
RtlMemory.c
RtlSplayTree.c
+ RtlUnicodeString.c
diff --git a/rostests/kmtests/rtl/RtlUnicodeString.c b/rostests/kmtests/rtl/RtlUnicodeString.c
new file mode 100644
index 00000000000..c69bf0a228e
--- /dev/null
+++ b/rostests/kmtests/rtl/RtlUnicodeString.c
@@ -0,0 +1,183 @@
+/*
+ * PROJECT: ReactOS kernel-mode tests
+ * LICENSE: GPLv2+ - See COPYING in the top level directory
+ * PURPOSE: Kernel-Mode Test Suite Runtime library unicode string functions test
+ * PROGRAMMER: Thomas Faber
+ */
+
+#define KMT_EMULATE_KERNEL
+#include
+
+#define StartSeh() ExceptionStatus = STATUS_SUCCESS; _SEH2_TRY {
+#define EndSeh(ExpectedStatus) } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { ExceptionStatus = _SEH2_GetExceptionCode(); } _SEH2_END; ok_eq_hex(ExceptionStatus, ExpectedStatus)
+
+static
+VOID
+TestFindCharInUnicodeString(VOID)
+{
+#ifdef KMT_USER_MODE
+ NTSTATUS ExceptionStatus;
+ NTSTATUS Status;
+ UNICODE_STRING String = RTL_CONSTANT_STRING(L"I am a string");
+ UNICODE_STRING Chars = RTL_CONSTANT_STRING(L"a");
+ UNICODE_STRING Chars2 = RTL_CONSTANT_STRING(L"A");
+ UNICODE_STRING Chars3 = RTL_CONSTANT_STRING(L"i");
+ UNICODE_STRING Chars4 = RTL_CONSTANT_STRING(L"G");
+ UNICODE_STRING ZeroLengthString;
+ USHORT Position;
+ ULONG LongPosition;
+
+ RtlInitUnicodeString(&ZeroLengthString, NULL);
+
+ /* Basic checks. Covered by Winetests */
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(0, &String, &Chars, &Position);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ ok_eq_uint(Position, 6);
+
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(1, &String, &Chars, &Position);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ ok_eq_uint(Position, 10);
+
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(2, &String, &Chars, &Position);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ ok_eq_uint(Position, 2);
+
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(3, &String, &Chars, &Position);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ ok_eq_uint(Position, 24);
+
+ /* Show that checks are case sensitive by default */
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(0, &String, &Chars2, &Position);
+ ok_eq_hex(Status, STATUS_NOT_FOUND);
+ ok_eq_uint(Position, 0);
+
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(1, &String, &Chars2, &Position);
+ ok_eq_hex(Status, STATUS_NOT_FOUND);
+ ok_eq_uint(Position, 0);
+
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(2, &String, &Chars3, &Position);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ ok_eq_uint(Position, 2);
+
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(3, &String, &Chars4, &Position);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ ok_eq_uint(Position, 24);
+
+ /* Show that 4 means case insensitive */
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(4, &String, &Chars2, &Position);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ ok_eq_uint(Position, 6);
+
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(5, &String, &Chars2, &Position);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ ok_eq_uint(Position, 10);
+
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(6, &String, &Chars3, &Position);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ ok_eq_uint(Position, 4);
+
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(7, &String, &Chars4, &Position);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ ok_eq_uint(Position, 22);
+
+ /* Show that Position is USHORT */
+ LongPosition = 0x55555555;
+ Status = RtlFindCharInUnicodeString(8, &String, &String, (PUSHORT)&LongPosition);
+ ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
+ ok_eq_ulong(LongPosition, 0x55550000UL);
+
+ /* Invalid flags */
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(8, &String, &String, &Position);
+ ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
+ ok_eq_uint(Position, 0);
+
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(0xFFFFFFF8, &String, &String, &Position);
+ ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
+ ok_eq_uint(Position, 0);
+
+ Position = 123;
+ Status = RtlFindCharInUnicodeString(0xFFFFFFFF, &String, &String, &Position);
+ ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
+ ok_eq_uint(Position, 0);
+
+ /* NULL for SearchString */
+ Position = 123;
+ StartSeh()
+ Status = RtlFindCharInUnicodeString(0, NULL, &String, &Position);
+ EndSeh(STATUS_ACCESS_VIOLATION);
+ ok_eq_uint(Position, 0);
+
+ /* NULL for SearchString and invalid flags */
+ Position = 123;
+ StartSeh()
+ Status = RtlFindCharInUnicodeString(8, NULL, &String, &Position);
+ EndSeh(STATUS_SUCCESS);
+ ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
+ ok_eq_uint(Position, 0);
+ ok_eq_uint(Position, 0);
+
+ /* NULL for SearchString with zero-length MatchString */
+ Position = 123;
+ StartSeh()
+ Status = RtlFindCharInUnicodeString(0, NULL, &ZeroLengthString, &Position);
+ EndSeh(STATUS_ACCESS_VIOLATION);
+ ok_eq_uint(Position, 0);
+
+ /* NULL for MatchString */
+ Position = 123;
+ StartSeh()
+ Status = RtlFindCharInUnicodeString(0, &String, NULL, &Position);
+ EndSeh(STATUS_ACCESS_VIOLATION);
+ ok_eq_uint(Position, 0);
+
+ /* This crashes in Windows, but not in ROS. I see no reason to add
+ * additional code or redesign the function to replicate that */
+#if 0
+ /* NULL for MatchString with zero-length SearchString */
+ Position = 123;
+ StartSeh()
+ Status = RtlFindCharInUnicodeString(0, &ZeroLengthString, NULL, &Position);
+ EndSeh(STATUS_ACCESS_VIOLATION);
+ ok_eq_uint(Position, 0);
+#endif
+
+ /* NULL for MatchString and invalid flags */
+ Position = 123;
+ StartSeh()
+ Status = RtlFindCharInUnicodeString(8, &String, NULL, &Position);
+ EndSeh(STATUS_SUCCESS);
+ ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
+ ok_eq_uint(Position, 0);
+
+ /* NULL for Position */
+ StartSeh()
+ Status = RtlFindCharInUnicodeString(0, &String, &String, NULL);
+ EndSeh(STATUS_SUCCESS);
+ ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
+
+ /* NULL for all three */
+ StartSeh()
+ Status = RtlFindCharInUnicodeString(0, NULL, NULL, NULL);
+ EndSeh(STATUS_SUCCESS);
+ ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
+#endif
+}
+
+START_TEST(RtlUnicodeString)
+{
+ TestFindCharInUnicodeString();
+}