Use Unicode literals

This commit is contained in:
Chris Thrasher 2025-02-02 23:25:18 -07:00
parent 52ef7c9955
commit 505fe43d5a
8 changed files with 62 additions and 50 deletions

View File

@ -274,6 +274,10 @@ macro(sfml_add_library module)
target_compile_definitions(${target} PUBLIC "SFML_STATIC") target_compile_definitions(${target} PUBLIC "SFML_STATIC")
endif() endif()
# Enable support for UTF-8 characters in source code
if(SFML_COMPILER_MSVC)
target_compile_options(${target} PRIVATE /utf-8)
endif()
endmacro() endmacro()
# add a new target which is a SFML example # add a new target which is a SFML example
@ -350,6 +354,11 @@ macro(sfml_add_example target)
if(SFML_OS_WINDOWS AND SFML_USE_MESA3D) if(SFML_OS_WINDOWS AND SFML_USE_MESA3D)
add_dependencies(${target} "install-mesa3d") add_dependencies(${target} "install-mesa3d")
endif() endif()
# Enable support for UTF-8 characters in source code
if(SFML_COMPILER_MSVC)
target_compile_options(${target} PRIVATE /utf-8)
endif()
endmacro() endmacro()
# add a new target which is a SFML test # add a new target which is a SFML test
@ -407,6 +416,11 @@ function(sfml_add_test target SOURCES DEPENDS)
endif() endif()
endif() endif()
# Enable support for UTF-8 characters in source code
if(SFML_COMPILER_MSVC)
target_compile_options(${target} PRIVATE /utf-8)
endif()
# Add the test # Add the test
catch_discover_tests(${target} WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) catch_discover_tests(${target} WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
endfunction() endfunction()

View File

@ -171,12 +171,12 @@ TEST_CASE("[Audio] sf::InputSoundFile")
SECTION("Polish filename") SECTION("Polish filename")
{ {
REQUIRE(inputSoundFile.openFromFile(U"Audio/ding-\u0144.flac")); REQUIRE(inputSoundFile.openFromFile(U"Audio/ding-ń.flac"));
} }
SECTION("Emoji filename") SECTION("Emoji filename")
{ {
REQUIRE(inputSoundFile.openFromFile(U"Audio/ding-\U0001F40C.flac")); REQUIRE(inputSoundFile.openFromFile(U"Audio/ding-🐌.flac"));
} }
CHECK(inputSoundFile.getSampleCount() == 87'798); CHECK(inputSoundFile.getSampleCount() == 87'798);
@ -196,12 +196,12 @@ TEST_CASE("[Audio] sf::InputSoundFile")
SECTION("Polish filename") SECTION("Polish filename")
{ {
REQUIRE(inputSoundFile.openFromFile(U"Audio/ding-\u0144.mp3")); REQUIRE(inputSoundFile.openFromFile(U"Audio/ding-ń.mp3"));
} }
SECTION("Emoji filename") SECTION("Emoji filename")
{ {
REQUIRE(inputSoundFile.openFromFile(U"Audio/ding-\U0001F40C.mp3")); REQUIRE(inputSoundFile.openFromFile(U"Audio/ding-🐌.mp3"));
} }
CHECK(inputSoundFile.getSampleCount() == 87'798); CHECK(inputSoundFile.getSampleCount() == 87'798);
@ -221,12 +221,12 @@ TEST_CASE("[Audio] sf::InputSoundFile")
SECTION("Polish filename") SECTION("Polish filename")
{ {
REQUIRE(inputSoundFile.openFromFile(U"Audio/doodle_pop-\u0144.ogg")); REQUIRE(inputSoundFile.openFromFile(U"Audio/doodle_pop-ń.ogg"));
} }
SECTION("Emoji filename") SECTION("Emoji filename")
{ {
REQUIRE(inputSoundFile.openFromFile(U"Audio/doodle_pop-\U0001F40C.ogg")); REQUIRE(inputSoundFile.openFromFile(U"Audio/doodle_pop-🐌.ogg"));
} }
CHECK(inputSoundFile.getSampleCount() == 2'116'992); CHECK(inputSoundFile.getSampleCount() == 2'116'992);
@ -246,12 +246,12 @@ TEST_CASE("[Audio] sf::InputSoundFile")
SECTION("Polish filename") SECTION("Polish filename")
{ {
REQUIRE(inputSoundFile.openFromFile(U"Audio/killdeer-\u0144.wav")); REQUIRE(inputSoundFile.openFromFile(U"Audio/killdeer-ń.wav"));
} }
SECTION("Emoji filename") SECTION("Emoji filename")
{ {
REQUIRE(inputSoundFile.openFromFile(U"Audio/killdeer-\U0001F40C.wav")); REQUIRE(inputSoundFile.openFromFile(U"Audio/killdeer-🐌.wav"));
} }
CHECK(inputSoundFile.getSampleCount() == 112'941); CHECK(inputSoundFile.getSampleCount() == 112'941);

View File

@ -140,12 +140,12 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
SECTION("Polish filename") SECTION("Polish filename")
{ {
REQUIRE(music.openFromFile(U"Audio/ding-\u0144.mp3")); REQUIRE(music.openFromFile(U"Audio/ding-ń.mp3"));
} }
SECTION("Emoji filename") SECTION("Emoji filename")
{ {
REQUIRE(music.openFromFile(U"Audio/ding-\U0001F40C.mp3")); REQUIRE(music.openFromFile(U"Audio/ding-🐌.mp3"));
} }
CHECK(music.getDuration() == sf::microseconds(1990884)); CHECK(music.getDuration() == sf::microseconds(1990884));

View File

@ -129,12 +129,12 @@ TEST_CASE("[Audio] sf::SoundBuffer", runAudioDeviceTests())
SECTION("Polish filename") SECTION("Polish filename")
{ {
REQUIRE(soundBuffer.loadFromFile(U"Audio/ding-\u0144.flac")); REQUIRE(soundBuffer.loadFromFile(U"Audio/ding-ń.flac"));
} }
SECTION("Emoji filename") SECTION("Emoji filename")
{ {
REQUIRE(soundBuffer.loadFromFile(U"Audio/ding-\U0001F40C.flac")); REQUIRE(soundBuffer.loadFromFile(U"Audio/ding-🐌.flac"));
} }
CHECK(soundBuffer.getSamples() != nullptr); CHECK(soundBuffer.getSamples() != nullptr);

View File

@ -266,16 +266,16 @@ TEST_CASE("[Graphics] sf::Image")
CHECK(!image.loadFromFile("this/does/not/exist.jpg")); CHECK(!image.loadFromFile("this/does/not/exist.jpg"));
// small n with tilde, from Spanish, outside of ASCII, inside common Latin 1 codepage // small n with tilde, from Spanish, outside of ASCII, inside common Latin 1 codepage
CHECK(!image.loadFromFile(std::filesystem::path(U"missing-file-\u00f1.png"))); CHECK(!image.loadFromFile(std::filesystem::path(U"missing-file-ñ.png")));
// small n with acute accent, from Polish, outside of Latin 1 codepage // small n with acute accent, from Polish, outside of Latin 1 codepage
CHECK(!image.loadFromFile(std::filesystem::path(U"missing-file-\u0144.png"))); CHECK(!image.loadFromFile(std::filesystem::path(U"missing-file-ń.png")));
// CJK symbol for Sun, outside of any European language codepage // CJK symbol for Sun, outside of any European language codepage
CHECK(!image.loadFromFile(std::filesystem::path(U"missing-file-\u65E5.png"))); CHECK(!image.loadFromFile(std::filesystem::path(U"missing-file-.png")));
// snail emoji, outside of Unicode Basic Multilingual Plane // snail emoji, outside of Unicode Basic Multilingual Plane
CHECK(!image.loadFromFile(std::filesystem::path(U"missing-file-\U0001F40C.png"))); CHECK(!image.loadFromFile(std::filesystem::path(U"missing-file-🐌.png")));
CHECK(image.getSize() == sf::Vector2u(0, 0)); CHECK(image.getSize() == sf::Vector2u(0, 0));
CHECK(image.getPixelsPtr() == nullptr); CHECK(image.getPixelsPtr() == nullptr);
@ -472,25 +472,25 @@ TEST_CASE("[Graphics] sf::Image")
SECTION("To Spanish Latin1 filename .png") SECTION("To Spanish Latin1 filename .png")
{ {
// small n with tilde, from Spanish, outside of ASCII, inside common Latin 1 codepage // small n with tilde, from Spanish, outside of ASCII, inside common Latin 1 codepage
filename /= U"test-\u00f1.png"; filename /= U"test-ñ.png";
} }
SECTION("To Polish filename .png") SECTION("To Polish filename .png")
{ {
// small n with acute accent, from Polish, outside of Latin 1 codepage // small n with acute accent, from Polish, outside of Latin 1 codepage
filename /= U"test-\u0144.png"; filename /= U"test-ń.png";
} }
SECTION("To Japanese CJK filename .png") SECTION("To Japanese CJK filename .png")
{ {
// CJK symbol for Sun, outside of any European language codepage // CJK symbol for Sun, outside of any European language codepage
filename /= U"test-\u65E5.png"; filename /= U"test-.png";
} }
SECTION("To emoji non-BMP Unicode filename .png") SECTION("To emoji non-BMP Unicode filename .png")
{ {
// snail emoji, outside of Unicode Basic Multilingual Plane // snail emoji, outside of Unicode Basic Multilingual Plane
filename /= U"test-\U0001F40C.png"; filename /= U"test-🐌.png";
} }
// Cannot test JPEG encoding due to it triggering UB in stbiw__jpg_writeBits // Cannot test JPEG encoding due to it triggering UB in stbiw__jpg_writeBits

View File

@ -425,12 +425,10 @@ TEST_CASE("[Graphics] sf::Shader", skipShaderFullTests())
SECTION("One shader with non-ASCII filename") SECTION("One shader with non-ASCII filename")
{ {
CHECK(shader.loadFromFile(U"Graphics/shader-\u0144.vert", sf::Shader::Type::Vertex) == CHECK(shader.loadFromFile(U"Graphics/shader-ń.vert", sf::Shader::Type::Vertex) == sf::Shader::isAvailable());
sf::Shader::isAvailable());
CHECK(static_cast<bool>(shader.getNativeHandle()) == sf::Shader::isAvailable()); CHECK(static_cast<bool>(shader.getNativeHandle()) == sf::Shader::isAvailable());
CHECK(shader.loadFromFile(U"Graphics/shader-\U0001F40C.vert", sf::Shader::Type::Vertex) == CHECK(shader.loadFromFile(U"Graphics/shader-🐌.vert", sf::Shader::Type::Vertex) == sf::Shader::isAvailable());
sf::Shader::isAvailable());
CHECK(static_cast<bool>(shader.getNativeHandle()) == sf::Shader::isAvailable()); CHECK(static_cast<bool>(shader.getNativeHandle()) == sf::Shader::isAvailable());
} }
} }

View File

@ -102,12 +102,12 @@ TEST_CASE("[System] sf::FileInputStream")
SECTION("From Polish filename") SECTION("From Polish filename")
{ {
REQUIRE(fileInputStream.open(U"System/test-\u0144.txt")); REQUIRE(fileInputStream.open(U"System/test-ń.txt"));
} }
SECTION("From emoji filename") SECTION("From emoji filename")
{ {
REQUIRE(fileInputStream.open(U"System/test-\U0001F40C.txt")); REQUIRE(fileInputStream.open(U"System/test-🐌.txt"));
} }
CHECK(fileInputStream.read(buffer.data(), 5) == 5); CHECK(fileInputStream.read(buffer.data(), 5) == 5);

View File

@ -353,14 +353,14 @@ TEST_CASE("[System] sf::String")
SECTION("UTF-32 character constructor") SECTION("UTF-32 character constructor")
{ {
const sf::String string = U'\U0010AFAF'; const sf::String string = U'🐌';
CHECK(std::string(string) == "\0"s); CHECK(std::string(string) == "\0"s);
CHECK(std::wstring(string) == select(L""s, L"\U0010AFAF"s)); CHECK(std::wstring(string) == select(L""s, L"🐌"s));
CHECK(string.toAnsiString() == "\0"s); CHECK(string.toAnsiString() == "\0"s);
CHECK(string.toWideString() == select(L""s, L"\U0010AFAF"s)); CHECK(string.toWideString() == select(L""s, L"🐌"s));
CHECK(string.toUtf8() == sf::U8String{0xF4, 0x8A, 0xBE, 0xAF}); CHECK(string.toUtf8() == sf::U8String{0xF0, 0x9F, 0x90, 0x8C});
CHECK(string.toUtf16() == u"\U0010AFAF"s); CHECK(string.toUtf16() == u"🐌"s);
CHECK(string.toUtf32() == U"\U0010AFAF"s); CHECK(string.toUtf32() == U"🐌"s);
CHECK(string.getSize() == 1); CHECK(string.getSize() == 1);
CHECK(!string.isEmpty()); CHECK(!string.isEmpty());
CHECK(string.getData() != nullptr); CHECK(string.getData() != nullptr);
@ -385,14 +385,14 @@ TEST_CASE("[System] sf::String")
SECTION("Non-empty string") SECTION("Non-empty string")
{ {
const sf::String string = U"\U0010ABCDrs"; const sf::String string = U"🐌rs";
CHECK(std::string(string) == "\0rs"s); CHECK(std::string(string) == "\0rs"s);
CHECK(std::wstring(string) == select(L"rs"s, L"\U0010ABCDrs"s)); CHECK(std::wstring(string) == select(L"rs"s, L"🐌rs"s));
CHECK(string.toAnsiString() == "\0rs"s); CHECK(string.toAnsiString() == "\0rs"s);
CHECK(string.toWideString() == select(L"rs"s, L"\U0010ABCDrs"s)); CHECK(string.toWideString() == select(L"rs"s, L"🐌rs"s));
CHECK(string.toUtf8() == sf::U8String{0xF4, 0x8A, 0xAF, 0x8D, 'r', 's'}); CHECK(string.toUtf8() == sf::U8String{0xF0, 0x9F, 0x90, 0x8C, 'r', 's'});
CHECK(string.toUtf16() == u"\U0010ABCDrs"s); CHECK(string.toUtf16() == u"🐌rs"s);
CHECK(string.toUtf32() == U"\U0010ABCDrs"s); CHECK(string.toUtf32() == U"🐌rs"s);
CHECK(string.getSize() == 3); CHECK(string.getSize() == 3);
CHECK(!string.isEmpty()); CHECK(!string.isEmpty());
CHECK(string.getData() != nullptr); CHECK(string.getData() != nullptr);
@ -401,14 +401,14 @@ TEST_CASE("[System] sf::String")
SECTION("UTF-32 string constructor") SECTION("UTF-32 string constructor")
{ {
const sf::String string = U"tuv\U00104321"s; const sf::String string = U"tuv🐌"s;
CHECK(std::string(string) == "tuv\0"s); CHECK(std::string(string) == "tuv\0"s);
CHECK(std::wstring(string) == select(L"tuv"s, L"tuv\U00104321"s)); CHECK(std::wstring(string) == select(L"tuv"s, L"tuv🐌"s));
CHECK(string.toAnsiString() == "tuv\0"s); CHECK(string.toAnsiString() == "tuv\0"s);
CHECK(string.toWideString() == select(L"tuv"s, L"tuv\U00104321"s)); CHECK(string.toWideString() == select(L"tuv"s, L"tuv🐌"s));
CHECK(string.toUtf8() == sf::U8String{'t', 'u', 'v', 0xF4, 0x84, 0x8C, 0xA1}); CHECK(string.toUtf8() == sf::U8String{'t', 'u', 'v', 0xF0, 0x9F, 0x90, 0x8C});
CHECK(string.toUtf16() == u"tuv\U00104321"s); CHECK(string.toUtf16() == u"tuv🐌"s);
CHECK(string.toUtf32() == U"tuv\U00104321"s); CHECK(string.toUtf32() == U"tuv🐌"s);
CHECK(string.getSize() == 4); CHECK(string.getSize() == 4);
CHECK(!string.isEmpty()); CHECK(!string.isEmpty());
CHECK(string.getData() != nullptr); CHECK(string.getData() != nullptr);
@ -461,15 +461,15 @@ TEST_CASE("[System] sf::String")
SECTION("fromUtf32()") SECTION("fromUtf32()")
{ {
constexpr std::array<char32_t, 4> characters{'w', 0x104321, 'y', 'z'}; constexpr std::array<char32_t, 4> characters{'w', U'🐌', 'y', 'z'};
const sf::String string = sf::String::fromUtf32(characters.begin(), characters.end()); const sf::String string = sf::String::fromUtf32(characters.begin(), characters.end());
CHECK(std::string(string) == "w\0yz"s); CHECK(std::string(string) == "w\0yz"s);
CHECK(std::wstring(string) == select(L"wyz"s, L"w\U00104321yz"s)); CHECK(std::wstring(string) == select(L"wyz"s, L"w🐌yz"s));
CHECK(string.toAnsiString() == "w\0yz"s); CHECK(string.toAnsiString() == "w\0yz"s);
CHECK(string.toWideString() == select(L"wyz"s, L"w\U00104321yz"s)); CHECK(string.toWideString() == select(L"wyz"s, L"w🐌yz"s));
CHECK(string.toUtf8() == sf::U8String{'w', 0xF4, 0x84, 0x8C, 0xA1, 'y', 'z'}); CHECK(string.toUtf8() == sf::U8String{'w', 0xF0, 0x9F, 0x90, 0x8C, 'y', 'z'});
CHECK(string.toUtf16() == u"w\U00104321yz"s); CHECK(string.toUtf16() == u"w🐌yz"s);
CHECK(string.toUtf32() == U"w\U00104321yz"s); CHECK(string.toUtf32() == U"w🐌yz"s);
CHECK(string.getSize() == 4); CHECK(string.getSize() == 4);
CHECK(!string.isEmpty()); CHECK(!string.isEmpty());
CHECK(string.getData() != nullptr); CHECK(string.getData() != nullptr);