diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 86c0da8..50de854 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -63,6 +63,7 @@ wdk_add_driver(kf-test WINVER NTDDI_WIN10 STL AutoSpinLockTest.cpp EResourceSharedLockTest.cpp RecursiveAutoSpinLockTest.cpp + UStringBuilderTest.cpp USimpleStringTest.cpp ) diff --git a/test/UStringBuilderTest.cpp b/test/UStringBuilderTest.cpp new file mode 100644 index 0000000..0d9d991 --- /dev/null +++ b/test/UStringBuilderTest.cpp @@ -0,0 +1,170 @@ +#include "pch.h" +#include +#include + +using namespace kf; + +SCENARIO("UStringBuilder") +{ + GIVEN("A default constructed builder") + { + UStringBuilder sb; + + THEN("It holds an empty string") + { + REQUIRE(sb.string().charLength() == 0); + REQUIRE(sb.string().maxCharLength() == 0); + } + + WHEN("reserve(0) is called") + { + NTSTATUS status = sb.reserve(0); + + THEN("It succeeds and remains empty") + { + REQUIRE_NT_SUCCESS(status); + REQUIRE(sb.string().charLength() == 0); + REQUIRE(sb.string().maxCharLength() == 0); + } + } + + WHEN("reserve(10) is called") + { + NTSTATUS status = sb.reserve(10); + + THEN("Capacity grows and length stays 0") + { + REQUIRE_NT_SUCCESS(status); + REQUIRE(sb.string().charLength() == 0); + REQUIRE(sb.string().maxCharLength() == 10); + } + } + } + + GIVEN("An empty builder") + { + UStringBuilder sb; + + WHEN("A single PCWSTR is appended") + { + NTSTATUS status = sb.append(L"abc"); + + THEN("The resulting string equals 'abc'") + { + REQUIRE_NT_SUCCESS(status); + REQUIRE(sb.string().equals(L"abc")); + } + } + + WHEN("A single USimpleString is appended") + { + NTSTATUS status = sb.append(USimpleString(L"def")); + THEN("The resulting string equals 'def'") + { + REQUIRE_NT_SUCCESS(status); + REQUIRE(sb.string().equals(L"def")); + } + } + + WHEN("A single UNICODE_STRING is appended") + { + UNICODE_STRING us = RTL_CONSTANT_STRING(L"ghi"); + NTSTATUS status = sb.append(us); + THEN("The resulting string equals 'ghi'") + { + REQUIRE_NT_SUCCESS(status); + REQUIRE(sb.string().equals(L"ghi")); + } + } + + WHEN("A single UString is appended") + { + UString us; + REQUIRE_NT_SUCCESS(us.init(L"xyz")); + + NTSTATUS status = sb.append(us); + THEN("The resulting string equals 'xyz'") + { + REQUIRE_NT_SUCCESS(status); + REQUIRE(sb.string().equals(L"xyz")); + } + } + + WHEN("A single span is appended") + { + const wchar_t data[] = { L'm', L'n', L'o' }; + NTSTATUS status = sb.append(span{ data }); + + THEN("The resulting string equals 'mno'") + { + REQUIRE_NT_SUCCESS(status); + REQUIRE(sb.string().equals(L"mno")); + } + } + + WHEN("A single span is appended") + { + // UTF-16LE bytes for "uvw": u=0x0075, v=0x0076, w=0x0077 + const std::byte bytes[] = + { + std::byte{0x75}, std::byte{0x00}, + std::byte{0x76}, std::byte{0x00}, + std::byte{0x77}, std::byte{0x00} + }; + NTSTATUS status = sb.append(span { bytes }); + + THEN("The resulting string equals 'uvw'") + { + REQUIRE_NT_SUCCESS(status); + REQUIRE(sb.string().equals(L"uvw")); + } + } + + WHEN("USimpleString and PCWSTR are appended in sequence") + { + NTSTATUS status1 = sb.append(L"ab"); + NTSTATUS status2 = sb.append(USimpleString(L"cd")); + NTSTATUS status3 = sb.append(L""); + + THEN("They concatenate to 'abcd'") + { + REQUIRE_NT_SUCCESS(status1); + REQUIRE_NT_SUCCESS(status2); + REQUIRE_NT_SUCCESS(status3); + REQUIRE(sb.string().equals(L"abcd")); + } + } + + WHEN("Variadic append with multiple arguments is used") + { + NTSTATUS status = sb.append(USimpleString(L"ab"), USimpleString(L"cd"), L"ef"); + + THEN("All parts are appended in order") + { + REQUIRE_NT_SUCCESS(status); + REQUIRE(sb.string().equals(L"abcdef")); + } + } + } + + GIVEN("A builder with content 'Hello'") + { + UStringBuilder sb; + REQUIRE_NT_SUCCESS(sb.append(L"Hello")); + + WHEN("reserve is called with a smaller size than current length") + { + // Note: current charLength is 5, reserve(3) will reallocate to 3 and truncate + NTSTATUS status = sb.reserve(3); + + THEN("It truncates the current content") + { + REQUIRE_NT_SUCCESS(status); + REQUIRE(sb.string().charLength() == 3); + REQUIRE(sb.string().maxCharLength() == 3); + REQUIRE(sb.string().equals(L"Hel")); + } + } + } +} + diff --git a/test/pch.h b/test/pch.h index 5e51399..80e5a60 100644 --- a/test/pch.h +++ b/test/pch.h @@ -4,6 +4,7 @@ #include #include #include +#include #include // TODO: move this default implementation to kf