/** * @file tests/unit/platform/windows/test_utf_utils.cpp * @brief Test src/platform/windows/utf_utils.cpp UTF conversion functions. */ #include "../../../tests_common.h" #include #include #ifdef _WIN32 #include #include #endif #ifdef _WIN32 /** * @brief Test fixture for utf_utils namespace functions */ class UtfUtilsTest: public testing::Test {}; TEST_F(UtfUtilsTest, FromUtf8WithEmptyString) { const std::string empty_string = ""; const std::wstring result = utf_utils::from_utf8(empty_string); EXPECT_TRUE(result.empty()) << "Empty UTF-8 string should produce empty wide string"; } TEST_F(UtfUtilsTest, ToUtf8WithEmptyWideString) { const std::wstring empty_wstring = L""; const std::string result = utf_utils::to_utf8(empty_wstring); EXPECT_TRUE(result.empty()) << "Empty wide string should produce empty UTF-8 string"; } TEST_F(UtfUtilsTest, FromUtf8WithBasicString) { const std::string test_string = "Hello World"; const std::wstring result = utf_utils::from_utf8(test_string); EXPECT_EQ(result, L"Hello World") << "Basic ASCII string should convert correctly"; } TEST_F(UtfUtilsTest, ToUtf8WithBasicWideString) { const std::wstring test_wstring = L"Hello World"; const std::string result = utf_utils::to_utf8(test_wstring); EXPECT_EQ(result, "Hello World") << "Basic wide string should convert correctly"; } TEST_F(UtfUtilsTest, RoundTripConversionBasic) { const std::string original = "Test String"; const std::wstring wide = utf_utils::from_utf8(original); const std::string converted_back = utf_utils::to_utf8(wide); EXPECT_EQ(original, converted_back) << "Round trip conversion should preserve basic string"; } TEST_F(UtfUtilsTest, FromUtf8WithQuotationMarks) { // Test various quotation marks that might appear in device names const std::string single_quote = "Device 'Audio' Output"; const std::string double_quote = "Device \"Audio\" Output"; const std::string left_quote = "Device \u{2018}Audio\u{2019} Output"; // Unicode left/right single quotes const std::string right_quote = "Device \u{2019}Audio\u{2018} Output"; // Unicode right/left single quotes const std::string left_double = "Device \u{201C}Audio\u{201D} Output"; // Unicode left/right double quotes const std::string right_double = "Device \u{201D}Audio\u{201C} Output"; // Unicode right/left double quotes const std::wstring result1 = utf_utils::from_utf8(single_quote); const std::wstring result2 = utf_utils::from_utf8(double_quote); const std::wstring result3 = utf_utils::from_utf8(left_quote); const std::wstring result4 = utf_utils::from_utf8(right_quote); const std::wstring result5 = utf_utils::from_utf8(left_double); const std::wstring result6 = utf_utils::from_utf8(right_double); EXPECT_EQ(result1, L"Device 'Audio' Output") << "Single quote conversion failed"; EXPECT_EQ(result2, L"Device \"Audio\" Output") << "Double quote conversion failed"; EXPECT_EQ(result3, L"Device \u{2018}Audio\u{2019} Output") << "Left quote conversion failed"; EXPECT_EQ(result4, L"Device \u{2019}Audio\u{2018} Output") << "Right quote conversion failed"; EXPECT_EQ(result5, L"Device \u{201C}Audio\u{201D} Output") << "Left double quote conversion failed"; EXPECT_EQ(result6, L"Device \u{201D}Audio\u{201C} Output") << "Right double quote conversion failed"; } TEST_F(UtfUtilsTest, FromUtf8WithTrademarkSymbols) { // Test trademark and copyright symbols const std::string trademark = "Audio Device™"; const std::string registered = "Audio Device®"; const std::string copyright = "Audio Device©"; const std::string combined = "Realtek® Audio™"; const std::wstring result1 = utf_utils::from_utf8(trademark); const std::wstring result2 = utf_utils::from_utf8(registered); const std::wstring result3 = utf_utils::from_utf8(copyright); const std::wstring result4 = utf_utils::from_utf8(combined); EXPECT_EQ(result1, L"Audio Device™") << "Trademark symbol conversion failed"; EXPECT_EQ(result2, L"Audio Device®") << "Registered symbol conversion failed"; EXPECT_EQ(result3, L"Audio Device©") << "Copyright symbol conversion failed"; EXPECT_EQ(result4, L"Realtek® Audio™") << "Combined symbols conversion failed"; } TEST_F(UtfUtilsTest, FromUtf8WithAccentedCharacters) { // Test accented characters that might appear in international device names const std::string french = "Haut-parleur à haute qualité"; const std::string spanish = "Altavoz ñáéíóú"; const std::string german = "Lautsprecher äöü"; const std::string mixed = "àáâãäåæçèéêë"; const std::wstring result1 = utf_utils::from_utf8(french); const std::wstring result2 = utf_utils::from_utf8(spanish); const std::wstring result3 = utf_utils::from_utf8(german); const std::wstring result4 = utf_utils::from_utf8(mixed); EXPECT_EQ(result1, L"Haut-parleur à haute qualité") << "French accents conversion failed"; EXPECT_EQ(result2, L"Altavoz ñáéíóú") << "Spanish accents conversion failed"; EXPECT_EQ(result3, L"Lautsprecher äöü") << "German accents conversion failed"; EXPECT_EQ(result4, L"àáâãäåæçèéêë") << "Mixed accents conversion failed"; } TEST_F(UtfUtilsTest, FromUtf8WithSpecialSymbols) { // Test various special symbols const std::string math_symbols = "Audio @ 44.1kHz ± 0.1%"; const std::string punctuation = "Audio Device #1 & #2"; const std::string programming = "Device $%^&*()"; const std::string mixed_symbols = "Audio™ @#$%^&*()"; const std::wstring result1 = utf_utils::from_utf8(math_symbols); const std::wstring result2 = utf_utils::from_utf8(punctuation); const std::wstring result3 = utf_utils::from_utf8(programming); const std::wstring result4 = utf_utils::from_utf8(mixed_symbols); EXPECT_EQ(result1, L"Audio @ 44.1kHz ± 0.1%") << "Math symbols conversion failed"; EXPECT_EQ(result2, L"Audio Device #1 & #2") << "Punctuation conversion failed"; EXPECT_EQ(result3, L"Device $%^&*()") << "Programming symbols conversion failed"; EXPECT_EQ(result4, L"Audio™ @#$%^&*()") << "Mixed symbols conversion failed"; } TEST_F(UtfUtilsTest, ToUtf8WithQuotationMarks) { // Test various quotation marks conversion from wide to UTF-8 const std::wstring single_quote = L"Device 'Audio' Output"; const std::wstring double_quote = L"Device \"Audio\" Output"; const std::wstring left_quote = L"Device \u{2018}Audio\u{2019} Output"; // Unicode left/right single quotes const std::wstring right_quote = L"Device \u{2019}Audio\u{2018} Output"; // Unicode right/left single quotes const std::wstring left_double = L"Device \u{201C}Audio\u{201D} Output"; // Unicode left/right double quotes const std::wstring right_double = L"Device \u{201D}Audio\u{201C} Output"; // Unicode right/left double quotes const std::string result1 = utf_utils::to_utf8(single_quote); const std::string result2 = utf_utils::to_utf8(double_quote); const std::string result3 = utf_utils::to_utf8(left_quote); const std::string result4 = utf_utils::to_utf8(right_quote); const std::string result5 = utf_utils::to_utf8(left_double); const std::string result6 = utf_utils::to_utf8(right_double); EXPECT_EQ(result1, "Device 'Audio' Output") << "Single quote to UTF-8 conversion failed"; EXPECT_EQ(result2, "Device \"Audio\" Output") << "Double quote to UTF-8 conversion failed"; EXPECT_EQ(result3, "Device \u{2018}Audio\u{2019} Output") << "Left quote to UTF-8 conversion failed"; EXPECT_EQ(result4, "Device \u{2019}Audio\u{2018} Output") << "Right quote to UTF-8 conversion failed"; EXPECT_EQ(result5, "Device \u{201C}Audio\u{201D} Output") << "Left double quote to UTF-8 conversion failed"; EXPECT_EQ(result6, "Device \u{201D}Audio\u{201C} Output") << "Right double quote to UTF-8 conversion failed"; } TEST_F(UtfUtilsTest, ToUtf8WithTrademarkSymbols) { // Test trademark and copyright symbols conversion from wide to UTF-8 const std::wstring trademark = L"Audio Device™"; const std::wstring registered = L"Audio Device®"; const std::wstring copyright = L"Audio Device©"; const std::wstring combined = L"Realtek® Audio™"; const std::string result1 = utf_utils::to_utf8(trademark); const std::string result2 = utf_utils::to_utf8(registered); const std::string result3 = utf_utils::to_utf8(copyright); const std::string result4 = utf_utils::to_utf8(combined); EXPECT_EQ(result1, "Audio Device™") << "Trademark symbol to UTF-8 conversion failed"; EXPECT_EQ(result2, "Audio Device®") << "Registered symbol to UTF-8 conversion failed"; EXPECT_EQ(result3, "Audio Device©") << "Copyright symbol to UTF-8 conversion failed"; EXPECT_EQ(result4, "Realtek® Audio™") << "Combined symbols to UTF-8 conversion failed"; } TEST_F(UtfUtilsTest, RoundTripConversionWithSpecialCharacters) { // Test round trip conversion with various special characters const std::string quotes = "Device 'Audio' with \u{201C}Special\u{201D} Characters"; const std::string symbols = "Realtek® Audio™ @ 44.1kHz ± 0.1%"; const std::string accents = "Haut-parleur àáâãäåæçèéêë"; const std::string mixed = "Audio™ 'Device' @#$%^&*() ñáéíóú"; // Convert to wide and back const std::wstring wide1 = utf_utils::from_utf8(quotes); const std::wstring wide2 = utf_utils::from_utf8(symbols); const std::wstring wide3 = utf_utils::from_utf8(accents); const std::wstring wide4 = utf_utils::from_utf8(mixed); const std::string back1 = utf_utils::to_utf8(wide1); const std::string back2 = utf_utils::to_utf8(wide2); const std::string back3 = utf_utils::to_utf8(wide3); const std::string back4 = utf_utils::to_utf8(wide4); EXPECT_EQ(quotes, back1) << "Round trip failed for quotes"; EXPECT_EQ(symbols, back2) << "Round trip failed for symbols"; EXPECT_EQ(accents, back3) << "Round trip failed for accents"; EXPECT_EQ(mixed, back4) << "Round trip failed for mixed characters"; } TEST_F(UtfUtilsTest, RealAudioDeviceNames) { // Test with realistic audio device names that contain special characters const std::string realtek = "Realtek® High Definition Audio"; const std::string creative = "Creative Sound Blaster™ X-Fi"; const std::string logitech = "Logitech G533 Gaming Headset"; const std::string bluetooth = "Sony WH-1000XM4 'Wireless' Headphones"; const std::string usb = "USB Audio Device @ 48kHz"; // Test conversion to wide const std::wstring wide_realtek = utf_utils::from_utf8(realtek); const std::wstring wide_creative = utf_utils::from_utf8(creative); const std::wstring wide_logitech = utf_utils::from_utf8(logitech); const std::wstring wide_bluetooth = utf_utils::from_utf8(bluetooth); const std::wstring wide_usb = utf_utils::from_utf8(usb); EXPECT_FALSE(wide_realtek.empty()) << "Realtek device name conversion failed"; EXPECT_FALSE(wide_creative.empty()) << "Creative device name conversion failed"; EXPECT_FALSE(wide_logitech.empty()) << "Logitech device name conversion failed"; EXPECT_FALSE(wide_bluetooth.empty()) << "Bluetooth device name conversion failed"; EXPECT_FALSE(wide_usb.empty()) << "USB device name conversion failed"; // Test round trip EXPECT_EQ(realtek, utf_utils::to_utf8(wide_realtek)) << "Realtek round trip failed"; EXPECT_EQ(creative, utf_utils::to_utf8(wide_creative)) << "Creative round trip failed"; EXPECT_EQ(logitech, utf_utils::to_utf8(wide_logitech)) << "Logitech round trip failed"; EXPECT_EQ(bluetooth, utf_utils::to_utf8(wide_bluetooth)) << "Bluetooth round trip failed"; EXPECT_EQ(usb, utf_utils::to_utf8(wide_usb)) << "USB round trip failed"; } TEST_F(UtfUtilsTest, InvalidUtf8Sequences) { // Test with invalid UTF-8 sequences - should return empty string const std::string invalid1 = "Test\x{FF}\x{FE}\x{FD}"; // Invalid UTF-8 bytes const std::string invalid2 = "Test\x{80}\x{81}\x{82}"; // Invalid continuation bytes const std::wstring result1 = utf_utils::from_utf8(invalid1); const std::wstring result2 = utf_utils::from_utf8(invalid2); // The function should return empty string for invalid UTF-8 sequences EXPECT_TRUE(result1.empty()) << "Invalid UTF-8 sequence should return empty string"; EXPECT_TRUE(result2.empty()) << "Invalid UTF-8 sequence should return empty string"; } TEST_F(UtfUtilsTest, LongStringsWithSpecialCharacters) { // Test with longer strings containing many special characters std::string long_special = "Device™ with 'special' characters: àáâãäåæçèéêë ñáéíóú äöü "; for (int i = 0; i < 10; ++i) { long_special += "Audio® Device™ @#$%^&*() "; } const std::wstring wide_result = utf_utils::from_utf8(long_special); const std::string back_result = utf_utils::to_utf8(wide_result); EXPECT_FALSE(wide_result.empty()) << "Long string conversion should not be empty"; EXPECT_EQ(long_special, back_result) << "Long string round trip should preserve content"; } #else // For non-Windows platforms, the utf_utils namespace doesn't exist TEST(UtfUtilsTest, UtfUtilsNotAvailableOnNonWindows) { GTEST_SKIP() << "utf_utils namespace is Windows-specific"; } #endif